diff options
1362 files changed, 24492 insertions, 11982 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3873a020b75..b45246eb4ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,19 +48,19 @@ jobs: include: - name: mingw-check tidy: false - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: mingw-check-tidy tidy: true - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: x86_64-gnu-llvm-14 tidy: false - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: x86_64-gnu-tools tidy: false - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} timeout-minutes: 600 runs-on: "${{ matrix.os }}" @@ -181,136 +181,136 @@ jobs: - ARM64 - linux - name: arm-android - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: armhf-gnu - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-aarch64-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-android - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-arm-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-armhf-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-armv7-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-i586-gnu-i586-i686-musl - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-i686-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-mips-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-mips64-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-mips64el-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-mipsel-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-powerpc-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-powerpc64-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-powerpc64le-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-riscv64-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-s390x-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-various-1 - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-various-2 - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-x86_64-freebsd - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-x86_64-illumos - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-x86_64-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-x86_64-linux-alt env: IMAGE: dist-x86_64-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb - name: dist-x86_64-musl - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: dist-x86_64-netbsd - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: i686-gnu - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: i686-gnu-nopt - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: mingw-check - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: test-various - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: wasm32 - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: x86_64-gnu - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: x86_64-gnu-stable env: IMAGE: x86_64-gnu RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable CI_ONLY_WHEN_CHANNEL: nightly - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb - name: x86_64-gnu-aux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: x86_64-gnu-debug - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: x86_64-gnu-distcheck - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: x86_64-gnu-llvm-15 env: RUST_BACKTRACE: 1 - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb - name: x86_64-gnu-llvm-14 env: RUST_BACKTRACE: 1 - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb - name: x86_64-gnu-llvm-14-stage1 env: RUST_BACKTRACE: 1 - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb - name: x86_64-gnu-nopt - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} - name: x86_64-gnu-tools env: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb - name: dist-x86_64-apple env: SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin" @@ -386,80 +386,80 @@ jobs: env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" SCRIPT: make ci-subset-1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: x86_64-msvc-2 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" SCRIPT: make ci-subset-2 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: i686-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc" SCRIPT: make ci-subset-1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: i686-msvc-2 env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc" SCRIPT: make ci-subset-2 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: x86_64-msvc-cargo env: SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld" - os: windows-latest-xl + os: windows-2019-8core-32gb - name: x86_64-msvc-tools env: SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json" DEPLOY_TOOLSTATES_JSON: toolstates-windows.json - os: windows-latest-xl + os: windows-2019-8core-32gb - name: i686-mingw-1 env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" SCRIPT: make ci-mingw-subset-1 NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: i686-mingw-2 env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" SCRIPT: make ci-mingw-subset-2 NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - 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 --enable-full-tools --enable-profiler" SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: dist-i686-msvc env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler" SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - 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 bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 WINDOWS_SDK_20348_HACK: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: dist-i686-mingw env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler" @@ -467,7 +467,7 @@ jobs: SCRIPT: python x.py dist bootstrap --include-default-paths CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: dist-x86_64-mingw env: SCRIPT: python x.py dist bootstrap --include-default-paths @@ -475,12 +475,12 @@ jobs: NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-latest-xl + os: windows-2019-8core-32gb - name: dist-x86_64-msvc-alt env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-extended --enable-profiler" SCRIPT: python x.py dist bootstrap --include-default-paths - os: windows-latest-xl + os: windows-2019-8core-32gb timeout-minutes: 600 runs-on: "${{ matrix.os }}" steps: @@ -595,7 +595,7 @@ jobs: matrix: include: - name: dist-x86_64-linux - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb env: {} timeout-minutes: 600 runs-on: "${{ matrix.os }}" diff --git a/.gitignore b/.gitignore index ce797a7a837..485968d9c56 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ Session.vim .project .favorites.json .settings/ +.vs/ ## Tool .valgrindrc @@ -42,6 +43,7 @@ no_llvm_build /llvm/ /mingw-build/ build/ +!/compiler/rustc_mir_build/src/build/ /build-rust-analyzer/ /dist/ /unicode-downloads diff --git a/.mailmap b/.mailmap index 715bc4d3085..9148b79e980 100644 --- a/.mailmap +++ b/.mailmap @@ -29,6 +29,8 @@ Alexander Ronald Altman <alexanderaltman@me.com> Alexandre Martin <martin.alex32@hotmail.fr> Alexis Beingessner <a.beingessner@gmail.com> Alfie John <alfie@alfie.wtf> Alfie John <alfiej@fastmail.fm> +Alona Enraght-Moony <code@alona.page> <nixon.emoony@gmail.com> +Alona Enraght-Moony <code@alona.page> <nixon@caminus.local> Amos Onn <amosonn@gmail.com> Ana-Maria Mihalache <mihalacheana.maria@yahoo.com> Anatoly Ikorsky <aikorsky@gmail.com> @@ -415,7 +417,6 @@ Nicolas Abram <abramlujan@gmail.com> Nicole Mazzuca <npmazzuca@gmail.com> Nif Ward <nif.ward@gmail.com> Nika Layzell <nika@thelayzells.com> <michael@thelayzells.com> -Nixon Enraght-Moony <nixon.emoony@gmail.com> NODA Kai <nodakai@gmail.com> oliver <16816606+o752d@users.noreply.github.com> Oliver Middleton <olliemail27@gmail.com> <ollie27@users.noreply.github.com> diff --git a/Cargo.lock b/Cargo.lock index 0c0b5d6ab3b..449f0c73588 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -898,7 +898,7 @@ dependencies = [ "tracing-subscriber", "unified-diff", "walkdir", - "winapi", + "windows 0.46.0", ] [[package]] @@ -1128,9 +1128,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.59+curl-7.86.0" +version = "0.4.61+curl-8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407" +checksum = "14d05c10f541ae6f3bc5b3d923c20001f47db7d5f0b2bc6ad16490133842db79" dependencies = [ "cc", "libc", @@ -1365,9 +1365,9 @@ dependencies = [ [[package]] name = "ena" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" dependencies = [ "log", ] @@ -2273,7 +2273,7 @@ dependencies = [ "dirs", "gix-path", "libc", - "windows", + "windows 0.43.0", ] [[package]] @@ -3103,9 +3103,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.25" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4" +checksum = "764dcbfc2e5f868bc1b566eb179dff1a06458fd0cff846aae2579392dd3f01a0" dependencies = [ "ammonia", "anyhow", @@ -4523,13 +4523,14 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_serialize", + "serde_json", "smallvec", "stable_deref_trait", "stacker", "tempfile", "thin-vec", "tracing", - "winapi", + "windows 0.46.0", ] [[package]] @@ -4588,7 +4589,7 @@ dependencies = [ "rustc_ty_utils", "serde_json", "tracing", - "winapi", + "windows 0.46.0", ] [[package]] @@ -4636,7 +4637,7 @@ dependencies = [ "termize", "tracing", "unicode-width", - "winapi", + "windows 0.46.0", ] [[package]] @@ -4826,6 +4827,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_expand", + "rustc_fs_util", "rustc_hir", "rustc_hir_analysis", "rustc_hir_typeck", @@ -4950,6 +4952,7 @@ dependencies = [ "rustc_errors", "rustc_expand", "rustc_feature", + "rustc_fs_util", "rustc_hir", "rustc_hir_pretty", "rustc_index", @@ -5277,7 +5280,7 @@ dependencies = [ "smallvec", "termize", "tracing", - "winapi", + "windows 0.46.0", ] [[package]] @@ -5294,6 +5297,7 @@ name = "rustc_span" version = "0.0.0" dependencies = [ "cfg-if", + "indexmap", "md-5", "rustc_arena", "rustc_data_structures", @@ -5334,6 +5338,7 @@ dependencies = [ "rustc_abi", "rustc_data_structures", "rustc_feature", + "rustc_fs_util", "rustc_index", "rustc_macros", "rustc_serialize", @@ -5458,13 +5463,13 @@ dependencies = [ "itertools", "minifier", "once_cell", - "rayon", "regex", "rustdoc-json-types", "serde", "serde_json", "smallvec", "tempfile", + "threadpool", "tracing", "tracing-subscriber", "tracing-tree", @@ -6210,6 +6215,15 @@ dependencies = [ ] [[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] name = "tidy" version = "0.1.0" dependencies = [ @@ -6900,6 +6914,15 @@ dependencies = [ ] [[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets", +] + +[[package]] name = "windows-sys" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6925,9 +6948,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -6940,45 +6963,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "writeable" diff --git a/RELEASES.md b/RELEASES.md index 4e974bbe974..a26dbbfa4f5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -125,12 +125,13 @@ Compiler - [Optimize field ordering by grouping m\*2^n-sized fields with equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/) - [Stabilize native library modifier `verbatim`.](https://github.com/rust-lang/rust/pull/104360/) -Added and removed targets: +Added, updated, and removed targets: - [Add a tier 3 target for PowerPC on AIX](https://github.com/rust-lang/rust/pull/102293/), `powerpc64-ibm-aix`. - [Add a tier 3 target for the Sony PlayStation 1](https://github.com/rust-lang/rust/pull/102689/), `mipsel-sony-psx`. - [Add tier 3 `no_std` targets for the QNX Neutrino RTOS](https://github.com/rust-lang/rust/pull/102701/), `aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`. +- [Promote UEFI targets to tier 2](https://github.com/rust-lang/rust/pull/103933/), `aarch64-unknown-uefi`, `i686-unknown-uefi`, and `x86_64-unknown-uefi`. - [Remove tier 3 `linuxkernel` targets](https://github.com/rust-lang/rust/pull/104015/) (not used by the actual kernel). Refer to Rust's [platform support page][platform-support-doc] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 6503bf2bab7..5d164bc4b3c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1184,6 +1184,15 @@ impl Expr { expr } + pub fn peel_parens_and_refs(&self) -> &Expr { + let mut expr = self; + while let ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) = &expr.kind + { + expr = inner; + } + expr + } + /// Attempts to reparse as `Ty` (for diagnostic purposes). pub fn to_ty(&self) -> Option<P<Ty>> { let kind = match &self.kind { diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 2e83b3e623f..c4771115cac 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -180,6 +180,12 @@ impl Attribute { self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str())) } + pub fn is_proc_macro_attr(&self) -> bool { + [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] + .iter() + .any(|kind| self.has_name(*kind)) + } + /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option<MetaItem> { match &self.kind { @@ -627,6 +633,22 @@ pub fn mk_attr_name_value_str( mk_attr(g, style, path, args, span) } +pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> { + attrs.iter().filter(move |attr| attr.has_name(name)) +} + +pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> { + filter_by_name(attrs, name).next() +} + +pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> { + find_by_name(attrs, name).and_then(|attr| attr.value_str()) +} + +pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { + find_by_name(attrs, name).is_some() +} + pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { items.iter().any(|item| item.has_name(name)) } diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index d021bea5eca..356b9bb6371 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -131,8 +131,8 @@ impl FormatArguments { &self.arguments[..] } - pub fn all_args_mut(&mut self) -> &mut [FormatArgument] { - &mut self.arguments[..] + pub fn all_args_mut(&mut self) -> &mut Vec<FormatArgument> { + &mut self.arguments } } diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 3a0af04f9eb..3893875e9a4 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -259,7 +259,6 @@ pub enum ExprPrecedence { Assign, AssignOp, - Box, AddrOf, Let, Unary, @@ -319,8 +318,7 @@ impl ExprPrecedence { ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8, // Unary, prefix - ExprPrecedence::Box - | ExprPrecedence::AddrOf + ExprPrecedence::AddrOf // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`. // However, this is not exactly right. When `let _ = a` is the LHS of a binop we // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b` diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 4095e225a80..72352b138cb 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -7,13 +7,172 @@ use rustc_hir as hir; use rustc_span::{ sym, symbol::{kw, Ident}, - Span, + Span, Symbol, }; +use std::borrow::Cow; impl<'hir> LoweringContext<'_, 'hir> { pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> { - expand_format_args(self, sp, fmt) + // Never call the const constructor of `fmt::Arguments` if the + // format_args!() had any arguments _before_ flattening/inlining. + let allow_const = fmt.arguments.all_args().is_empty(); + let mut fmt = Cow::Borrowed(fmt); + if self.tcx.sess.opts.unstable_opts.flatten_format_args { + fmt = flatten_format_args(fmt); + fmt = inline_literals(fmt); + } + expand_format_args(self, sp, &fmt, allow_const) + } +} + +/// Flattens nested `format_args!()` into one. +/// +/// Turns +/// +/// `format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3)` +/// +/// into +/// +/// `format_args!("a {} b{}! {}.", 1, 2, 3)`. +fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> { + let mut i = 0; + while i < fmt.template.len() { + if let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] + && let FormatTrait::Display | FormatTrait::Debug = &placeholder.format_trait + && let Ok(arg_index) = placeholder.argument.index + && let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs() + && let ExprKind::FormatArgs(_) = &arg.kind + // Check that this argument is not used by any other placeholders. + && fmt.template.iter().enumerate().all(|(j, p)| + i == j || + !matches!(p, FormatArgsPiece::Placeholder(placeholder) + if placeholder.argument.index == Ok(arg_index)) + ) + { + // Now we need to mutate the outer FormatArgs. + // If this is the first time, this clones the outer FormatArgs. + let fmt = fmt.to_mut(); + + // Take the inner FormatArgs out of the outer arguments, and + // replace it by the inner arguments. (We can't just put those at + // the end, because we need to preserve the order of evaluation.) + + let args = fmt.arguments.all_args_mut(); + let remaining_args = args.split_off(arg_index + 1); + let old_arg_offset = args.len(); + let mut fmt2 = &mut args.pop().unwrap().expr; // The inner FormatArgs. + let fmt2 = loop { // Unwrap the Expr to get to the FormatArgs. + match &mut fmt2.kind { + ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => fmt2 = inner, + ExprKind::FormatArgs(fmt2) => break fmt2, + _ => unreachable!(), + } + }; + + args.append(fmt2.arguments.all_args_mut()); + let new_arg_offset = args.len(); + args.extend(remaining_args); + + // Correct the indexes that refer to the arguments after the newly inserted arguments. + for_all_argument_indexes(&mut fmt.template, |index| { + if *index >= old_arg_offset { + *index -= old_arg_offset; + *index += new_arg_offset; + } + }); + + // Now merge the placeholders: + + let rest = fmt.template.split_off(i + 1); + fmt.template.pop(); // remove the placeholder for the nested fmt args. + // Insert the pieces from the nested format args, but correct any + // placeholders to point to the correct argument index. + for_all_argument_indexes(&mut fmt2.template, |index| *index += arg_index); + fmt.template.append(&mut fmt2.template); + fmt.template.extend(rest); + + // Don't increment `i` here, so we recurse into the newly added pieces. + } else { + i += 1; + } } + fmt +} + +/// Inline literals into the format string. +/// +/// Turns +/// +/// `format_args!("Hello, {}! {} {}", "World", 123, x)` +/// +/// into +/// +/// `format_args!("Hello, World! 123 {}", x)`. +fn inline_literals(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> { + let mut was_inlined = vec![false; fmt.arguments.all_args().len()]; + let mut inlined_anything = false; + + for i in 0..fmt.template.len() { + let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] else { continue }; + let Ok(arg_index) = placeholder.argument.index else { continue }; + + let mut literal = None; + + if let FormatTrait::Display = placeholder.format_trait + && placeholder.format_options == Default::default() + && let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs() + && let ExprKind::Lit(lit) = arg.kind + { + if let token::LitKind::Str | token::LitKind::StrRaw(_) = lit.kind + && let Ok(LitKind::Str(s, _)) = LitKind::from_token_lit(lit) + { + literal = Some(s); + } else if let token::LitKind::Integer = lit.kind + && let Ok(LitKind::Int(n, _)) = LitKind::from_token_lit(lit) + { + literal = Some(Symbol::intern(&n.to_string())); + } + } + + if let Some(literal) = literal { + // Now we need to mutate the outer FormatArgs. + // If this is the first time, this clones the outer FormatArgs. + let fmt = fmt.to_mut(); + // Replace the placeholder with the literal. + fmt.template[i] = FormatArgsPiece::Literal(literal); + was_inlined[arg_index] = true; + inlined_anything = true; + } + } + + // Remove the arguments that were inlined. + if inlined_anything { + let fmt = fmt.to_mut(); + + let mut remove = was_inlined; + + // Don't remove anything that's still used. + for_all_argument_indexes(&mut fmt.template, |index| remove[*index] = false); + + // Drop all the arguments that are marked for removal. + let mut remove_it = remove.iter(); + fmt.arguments.all_args_mut().retain(|_| remove_it.next() != Some(&true)); + + // Calculate the mapping of old to new indexes for the remaining arguments. + let index_map: Vec<usize> = remove + .into_iter() + .scan(0, |i, remove| { + let mapped = *i; + *i += !remove as usize; + Some(mapped) + }) + .collect(); + + // Correct the indexes that refer to arguments that have shifted position. + for_all_argument_indexes(&mut fmt.template, |index| *index = index_map[*index]); + } + + fmt } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -189,11 +348,26 @@ fn expand_format_args<'hir>( ctx: &mut LoweringContext<'_, 'hir>, macsp: Span, fmt: &FormatArgs, + allow_const: bool, ) -> hir::ExprKind<'hir> { + let mut incomplete_lit = String::new(); let lit_pieces = ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| { match piece { - &FormatArgsPiece::Literal(s) => Some(ctx.expr_str(fmt.span, s)), + &FormatArgsPiece::Literal(s) => { + // Coalesce adjacent literal pieces. + if let Some(FormatArgsPiece::Literal(_)) = fmt.template.get(i + 1) { + incomplete_lit.push_str(s.as_str()); + None + } else if !incomplete_lit.is_empty() { + incomplete_lit.push_str(s.as_str()); + let s = Symbol::intern(&incomplete_lit); + incomplete_lit.clear(); + Some(ctx.expr_str(fmt.span, s)) + } else { + Some(ctx.expr_str(fmt.span, s)) + } + } &FormatArgsPiece::Placeholder(_) => { // Inject empty string before placeholders when not already preceded by a literal piece. if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) { @@ -244,6 +418,18 @@ fn expand_format_args<'hir>( let arguments = fmt.arguments.all_args(); + if allow_const && arguments.is_empty() && argmap.is_empty() { + // Generate: + // <core::fmt::Arguments>::new_const(lit_pieces) + let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + macsp, + hir::LangItem::FormatArguments, + sym::new_const, + )); + let new_args = ctx.arena.alloc_from_iter([lit_pieces]); + return hir::ExprKind::Call(new, new_args); + } + // If the args array contains exactly all the original arguments once, // in order, we can use a simple array instead of a `match` construction. // However, if there's a yield point in any argument except the first one, @@ -290,25 +476,14 @@ fn expand_format_args<'hir>( let args_ident = Ident::new(sym::args, macsp); let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| { - if let Some(arg) = arguments.get(arg_index) { - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); - let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id); - let arg = ctx.arena.alloc(ctx.expr( - sp, - hir::ExprKind::Field( - args_ident_expr, - Ident::new(sym::integer(arg_index), macsp), - ), - )); - make_argument(ctx, sp, arg, ty) - } else { - ctx.expr( - macsp, - hir::ExprKind::Err( - ctx.tcx.sess.delay_span_bug(macsp, format!("no arg at {arg_index}")), - ), - ) - } + let arg = &arguments[arg_index]; + let sp = arg.expr.span.with_ctxt(macsp.ctxt()); + let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id); + let arg = ctx.arena.alloc(ctx.expr( + sp, + hir::ExprKind::Field(args_ident_expr, Ident::new(sym::integer(arg_index), macsp)), + )); + make_argument(ctx, sp, arg, ty) })); let elements: Vec<_> = arguments .iter() @@ -409,3 +584,22 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool { visitor.visit_expr(e); visitor.0 } + +fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) { + for piece in template { + let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; + if let Ok(index) = &mut placeholder.argument.index { + f(index); + } + if let Some(FormatCount::Argument(FormatArgPosition { index: Ok(index), .. })) = + &mut placeholder.format_options.width + { + f(index); + } + if let Some(FormatCount::Argument(FormatArgPosition { index: Ok(index), .. })) = + &mut placeholder.format_options.precision + { + f(index); + } + } +} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ea7fa02521e..0b6b02ba00f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2185,7 +2185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { def_id: self.local_def_id(param.id), name, span: self.lower_span(param.span()), - pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle), + pure_wrt_drop: attr::contains_name(¶m.attrs, sym::may_dangle), kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), source, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 539c822ea09..93c854cc809 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -799,11 +799,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_item(&mut self, item: &'a Item) { - if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) { + if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) { self.has_proc_macro_decls = true; } - if self.session.contains_name(&item.attrs, sym::no_mangle) { + if attr::contains_name(&item.attrs, sym::no_mangle) { self.check_nomangle_item_asciionly(item.ident, item.span); } @@ -973,7 +973,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) - && !self.session.contains_name(&item.attrs, sym::path) + && !attr::contains_name(&item.attrs, sym::path) { self.check_mod_file_item_asciionly(item.ident); } @@ -1248,7 +1248,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - if self.session.contains_name(&item.attrs, sym::no_mangle) { + if attr::contains_name(&item.attrs, sym::no_mangle) { self.check_nomangle_item_asciionly(item.ident, item.span); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 6a5d5614b1c..344a1e7f5e7 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; +use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd}; use rustc_errors::{Applicability, StashKey}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; @@ -232,7 +232,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Fn(..) => { - if self.sess.contains_name(&i.attrs, sym::start) { + if attr::contains_name(&i.attrs, sym::start) { gate_feature_post!( &self, start, @@ -245,7 +245,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Struct(..) => { - for attr in self.sess.filter_by_name(&i.attrs, sym::repr) { + for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(sym::simd) { gate_feature_post!( @@ -306,7 +306,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { match i.kind { ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => { - let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name); + let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); let links_to_llvm = link_name.map_or(false, |val| val.as_str().starts_with("llvm.")); if links_to_llvm { diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 3d240108b4a..d6dbdd3975e 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,6 +1,6 @@ //! Parsing and validation of builtin attributes -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; @@ -556,8 +556,8 @@ where (stab, const_stab, body_stab) } -pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> { - sess.first_attr_value_str_by_name(attrs, sym::crate_name) +pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> { + attr::first_attr_value_str_by_name(attrs, sym::crate_name) } #[derive(Clone, Debug)] @@ -1177,7 +1177,7 @@ fn allow_unstable<'a>( attrs: &'a [Attribute], symbol: Symbol, ) -> impl Iterator<Item = Symbol> + 'a { - let attrs = sess.filter_by_name(attrs, symbol); + let attrs = attr::filter_by_name(attrs, symbol); let list = attrs .filter_map(move |attr| { attr.meta_item_list().or_else(|| { diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 0762987e229..2cbd2e3bc0d 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -306,7 +306,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given - // pair of array indices are unequal, so that when `places_conflict` returns true, we + // pair of array indices are not equal, so that when `places_conflict` returns true, we // will be assured that two places being compared definitely denotes the same sets of // locations. let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f43b611f54e..75a3dd0c0f3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -24,6 +24,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::ObligationCtxt; use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; @@ -760,20 +761,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { else { return; }; // Try to find predicates on *generic params* that would allow copying `ty` let infcx = tcx.infer_ctxt().build(); - let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); - let cause = ObligationCause::new( - span, - self.mir_def_id(), - rustc_infer::traits::ObligationCauseCode::MiscObligation, - ); - let errors = rustc_trait_selection::traits::fully_solve_bound( - &infcx, - cause, - self.param_env, - // Erase any region vids from the type, which may not be resolved - infcx.tcx.erase_regions(ty), - copy_did, - ); + let ocx = ObligationCtxt::new(&infcx); + let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span)); + let cause = ObligationCause::misc(span, self.mir_def_id()); + + ocx.register_bound(cause, self.param_env, infcx.tcx.erase_regions(ty), copy_did); + let errors = ocx.select_all_or_error(); // Only emit suggestion if all required predicates are on generic let predicates: Result<Vec<_>, _> = errors @@ -1985,16 +1978,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let (place_desc, note) = if let Some(place_desc) = opt_place_desc { let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { match self.body.local_kind(local) { - LocalKind::ReturnPointer | LocalKind::Temp => { - bug!("temporary or return pointer with a name") + LocalKind::Temp if self.body.local_decls[local].is_user_variable() => { + "local variable " } - LocalKind::Var => "local variable ", LocalKind::Arg if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL => { "variable captured by `move` " } LocalKind::Arg => "function parameter ", + LocalKind::ReturnPointer | LocalKind::Temp => { + bug!("temporary or return pointer with a name") + } } } else { "local data " @@ -2008,16 +2003,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); let local = root_place.local; match self.body.local_kind(local) { - LocalKind::ReturnPointer | LocalKind::Temp => { - ("temporary value".to_string(), "temporary value created here".to_string()) - } LocalKind::Arg => ( "function parameter".to_string(), "function parameter borrowed here".to_string(), ), - LocalKind::Var => { + LocalKind::Temp if self.body.local_decls[local].is_user_variable() => { ("local binding".to_string(), "local binding introduced here".to_string()) } + LocalKind::ReturnPointer | LocalKind::Temp => { + ("temporary value".to_string(), "temporary value created here".to_string()) + } } }; @@ -2482,15 +2477,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let (place_description, assigned_span) = match local_decl { Some(LocalDecl { local_info: - Some(box LocalInfo::User( - ClearCrossCrate::Clear - | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + ClearCrossCrate::Set( + box LocalInfo::User(BindingForm::Var(VarBindingForm { opt_match_place: None, .. - })), - )) - | Some(box LocalInfo::StaticRef { .. }) - | None, + })) + | box LocalInfo::StaticRef { .. } + | box LocalInfo::Boring, + ), .. }) | None => (self.describe_any_place(place.as_ref()), assigned_span), diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 19855075ced..62b3f3ecfc3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor; use rustc_index::vec::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ - Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue, - Statement, StatementKind, TerminatorKind, + Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place, + Rvalue, Statement, StatementKind, TerminatorKind, }; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; @@ -220,7 +220,7 @@ impl<'tcx> BorrowExplanation<'tcx> { ); err.span_label(body.source_info(drop_loc).span, message); - if let Some(info) = &local_decl.is_block_tail { + if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() { if info.tail_result_is_ignored { // #85581: If the first mutable borrow's scope contains // the second borrow, this suggestion isn't helpful. diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index af705e6a80f..9f543b71c5f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -196,10 +196,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.body.local_decls[local].is_ref_for_guard() { continue; } - if let Some(box LocalInfo::StaticRef { def_id, .. }) = - &self.body.local_decls[local].local_info + if let LocalInfo::StaticRef { def_id, .. } = + *self.body.local_decls[local].local_info() { - buf.push_str(self.infcx.tcx.item_name(*def_id).as_str()); + buf.push_str(self.infcx.tcx.item_name(def_id).as_str()); ok = Ok(()); continue; } @@ -1078,7 +1078,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.param_env, tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)), def_id, - DUMMY_SP, ) } _ => false, diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 5e4c7292e59..3662bec0c76 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -102,14 +102,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // // opt_match_place is None for let [mut] x = ... statements, // whether or not the right-hand side is a place expression - if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { - opt_match_place: Some((opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - }, - )))) = local_decl.local_info + if let LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_match_place: Some((opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + pat_span: _, + })) = *local_decl.local_info() { let stmt_source_info = self.body.source_info(location); self.append_binding_error( @@ -478,9 +476,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut suggestions: Vec<(Span, String, String)> = Vec::new(); for local in binds_to { let bind_to = &self.body.local_decls[*local]; - if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { pat_span, .. }, - )))) = bind_to.local_info + if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span, .. })) = + *bind_to.local_info() { let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index eded913ae96..a8c216407f9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{ hir::place::PlaceBase, - mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location}, + mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, }; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, Symbol}; @@ -105,8 +105,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { reason = String::new(); } else { item_msg = access_place_desc; - let local_info = &self.body.local_decls[local].local_info; - if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { + let local_info = self.body.local_decls[local].local_info(); + if let LocalInfo::StaticRef { def_id, .. } = *local_info { let static_name = &self.infcx.tcx.item_name(def_id); reason = format!(", as `{static_name}` is an immutable static item"); } else { @@ -120,9 +120,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { && !self.upvars.is_empty() { item_msg = access_place_desc; - debug_assert!( - self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr() - ); + debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref()); debug_assert!(is_closure_or_generator( Place::ty_from( the_place_err.local, @@ -305,15 +303,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. }) = &self.body[location.block].statements.get(location.statement_index) { - match decl.local_info { - Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), - opt_ty_info: Some(sp), - opt_match_place: _, - pat_span: _, - }, - )))) => { + match *decl.local_info() { + LocalInfo::User(BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + opt_ty_info: Some(sp), + opt_match_place: _, + pat_span: _, + })) => { if suggest { err.span_note(sp, "the binding is already a mutable borrow"); } @@ -346,10 +342,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } else if decl.mutability.is_not() { if matches!( - decl.local_info, - Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( - hir::ImplicitSelfKind::MutRef - ),))) + decl.local_info(), + LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef)) ) { err.note( "as `Self` may be unsized, this call attempts to take `&mut &mut self`", @@ -474,30 +468,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { let local_decl = &self.body.local_decls[local]; - let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() { - ("&", "reference") - } else { - ("*const", "pointer") - }; + let (pointer_sigil, pointer_desc) = + if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") }; match self.local_names[local] { Some(name) if !local_decl.from_compiler_desugaring() => { - let label = match local_decl.local_info.as_deref().unwrap() { - LocalInfo::User(ClearCrossCrate::Set( - mir::BindingForm::ImplicitSelf(_), - )) => { + let label = match *local_decl.local_info() { + LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => { let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, local_decl); Some((true, span, suggestion)) } - LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info, - .. - }, - ))) => { + LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info, + .. + })) => { // check if the RHS is from desugaring let opt_assignment_rhs_span = self.body.find_assignments(local).first().map(|&location| { @@ -534,16 +521,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.infcx.tcx, local_decl, opt_assignment_rhs_span, - *opt_ty_info, + opt_ty_info, ) } else { - match local_decl.local_info.as_deref() { - Some(LocalInfo::User(ClearCrossCrate::Set( - mir::BindingForm::Var(mir::VarBindingForm { - opt_ty_info: None, - .. - }), - ))) => { + match local_decl.local_info() { + LocalInfo::User(mir::BindingForm::Var( + mir::VarBindingForm { + opt_ty_info: None, .. + }, + )) => { let (span, sugg) = suggest_ampmut_self( self.infcx.tcx, local_decl, @@ -555,7 +541,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.infcx.tcx, local_decl, opt_assignment_rhs_span, - *opt_ty_info, + opt_ty_info, ), } }; @@ -564,21 +550,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByReference(_), - .. - }, - ))) => { + LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByReference(_), + .. + })) => { let pattern_span = local_decl.source_info.span; suggest_ref_mut(self.infcx.tcx, pattern_span) .map(|replacement| (true, pattern_span, replacement)) } - LocalInfo::User(ClearCrossCrate::Clear) => { - bug!("saw cleared local state") - } - _ => unreachable!(), }; @@ -1151,20 +1131,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool { debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind()); - match local_decl.local_info.as_deref() { + match *local_decl.local_info() { // Check if mutably borrowing a mutable reference. - Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), .. - }, - )))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), - Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => { + LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + .. + })) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), + LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => { // Check if the user variable is a `&mut self` and we can therefore // suggest removing the `&mut`. // // Deliberately fall into this case for all implicit self types, // so that we don't fall in to the next case with them. - *kind == hir::ImplicitSelfKind::MutRef + kind == hir::ImplicitSelfKind::MutRef } _ if Some(kw::SelfLower) == local_name => { // Otherwise, check if the name is the `self` keyword - in which case @@ -1274,7 +1253,7 @@ fn suggest_ampmut<'tcx>( ( suggestability, highlight_span, - if local_decl.ty.is_region_ptr() { + if local_decl.ty.is_ref() { format!("&mut {}", ty_mut.ty) } else { format!("*mut {}", ty_mut.ty) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 5e77f6b190a..b7ce3afce7b 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -19,7 +19,6 @@ extern crate tracing; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -141,7 +140,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Bor debug!("Skipping borrowck because of injected body"); // Let's make up a borrowck result! Fun times! let result = BorrowCheckResult { - concrete_opaque_types: VecMap::new(), + concrete_opaque_types: FxIndexMap::default(), closure_requirements: None, used_mut_upvars: SmallVec::new(), tainted_by_errors: None, @@ -511,16 +510,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { .as_var() .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); - if cfg!(debug_assertions) { + if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() { debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); let ctxt = get_ctxt_fn(); let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(vid, ctxt); - - // This only makes sense if not called in a canonicalization context. If this - // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` - // or modify how we track nll region vars for that map. - assert!(matches!(prev, None)); + var_to_origin.insert(vid, ctxt); } next_region @@ -540,16 +534,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { .as_var() .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); - if cfg!(debug_assertions) { + if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() { debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); let ctxt = get_ctxt_fn(); let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(vid, ctxt); - - // This only makes sense if not called in a canonicalization context. If this - // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` - // or modify how we track nll region vars for that map. - assert!(matches!(prev, None)); + var_to_origin.insert(vid, ctxt); } next_region diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 96228338a4c..f0068fc9226 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -2,7 +2,7 @@ #![deny(rustc::diagnostic_outside_of_impl)] //! The entry point of the NLL borrow checker. -use rustc_data_structures::vec_map::VecMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; @@ -44,7 +44,7 @@ pub type PoloniusOutput = Output<RustcFacts>; /// closure requirements to propagate, and any generated errors. pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, + pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub polonius_input: Option<Box<AllFacts>>, pub polonius_output: Option<Rc<PoloniusOutput>>, pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>, @@ -377,7 +377,7 @@ pub(super) fn dump_annotation<'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, - opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, + opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, errors: &mut crate::error::BorrowckErrors<'tcx>, ) { let tcx = infcx.tcx; diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 905d8c42b28..03f175daca9 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -255,12 +255,13 @@ fn sccs_info<'cx, 'tcx>( let var_to_origin = infcx.reg_var_to_origin.borrow(); let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>(); - var_to_origin_sorted.sort_by(|a, b| a.0.cmp(&b.0)); - let mut debug_str = "region variables to origins:\n".to_string(); + var_to_origin_sorted.sort_by_key(|vto| vto.0); + + let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string(); for (reg_var, origin) in var_to_origin_sorted.into_iter() { - debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin)); + reg_vars_to_origins_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin)); } - debug!(debug_str); + debug!("{}", reg_vars_to_origins_str); let num_components = sccs.scc_data().ranges().len(); let mut components = vec![FxIndexSet::default(); num_components]; @@ -275,12 +276,12 @@ fn sccs_info<'cx, 'tcx>( for (scc_idx, reg_vars_origins) in components.iter().enumerate() { let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>(); components_str.push_str(&format!( - "{:?}: {:?})", + "{:?}: {:?},\n)", ConstraintSccIndex::from_usize(scc_idx), regions_info, )) } - debug!(components_str); + debug!("{}", components_str); // calculate the best representative for each component let components_representatives = components @@ -2216,7 +2217,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // is in the same SCC or something. In that case, find what // appears to be the most interesting point to report to the // user via an even more ad-hoc guess. - categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category)); + categorized_path.sort_by_key(|p| p.category); debug!("sorted_path={:#?}", categorized_path); (categorized_path.remove(0), extra_info) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 748c8b9e442..2b16655cf7d 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; @@ -61,9 +60,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'tcx>, - opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, - ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> { - let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new(); + opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> { + let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default(); let member_constraints: FxIndexMap<_, _> = self .member_constraints @@ -284,7 +283,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // hidden type is well formed even without those bounds. let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())); - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); // Require that the hidden type actually fulfills all the bounds of the opaque type, even without // the bounds that the function supplies. diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 3919c4793a0..c2a426bea09 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -10,7 +10,6 @@ use either::Either; use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -894,7 +893,7 @@ pub(crate) struct MirTypeckResults<'tcx> { pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) opaque_type_values: - VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, } /// A collection of region constraints that must be satisfied for the @@ -1180,10 +1179,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } Some(l) - if matches!( - body.local_decls[l].local_info, - Some(box LocalInfo::AggregateTemp) - ) => + if matches!(body.local_decls[l].local_info(), LocalInfo::AggregateTemp) => { ConstraintCategory::Usage } @@ -1684,7 +1680,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // - maybe we should make that a warning. return; } - LocalKind::Var | LocalKind::Temp => {} + LocalKind::Temp => {} } // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls @@ -2226,6 +2222,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } + CastKind::Transmute => { + span_mirbug!( + self, + rvalue, + "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR", + ); + } } } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index d96372fb99b..305e2c8fe8e 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -132,9 +132,12 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> let reg_var = reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); - let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info)); - assert!(matches!(prev, None)); + + if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() { + let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); + debug!(?reg_var); + var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info)); + } reg } @@ -149,14 +152,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> let reg_var = reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); - if cfg!(debug_assertions) { + if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() { let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(reg_var, RegionCtxt::Existential(None)); - - // It only makes sense to track region vars in non-canonicalization contexts. If this - // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` - // or modify how we track nll region vars for that map. - assert!(matches!(prev, None)); + var_to_origin.insert(reg_var, RegionCtxt::Existential(None)); } reg diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index db05c00d211..2b6fcc169be 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -6,7 +6,7 @@ use rustc_ast::{self as ast, AttrItem, AttrStyle}; use rustc_session::parse::ParseSess; use rustc_span::FileName; -pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { +pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { let mut parser = rustc_parse::new_parser_from_source_str( parse_sess, @@ -36,6 +36,4 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - start_span.to(end_span), )); } - - krate } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 4d753a2ed80..cc32739d083 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,7 +1,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use rustc_ast as ast; -use rustc_ast::{walk_list, EnumDef, VariantData}; +use rustc_ast::{attr, walk_list, EnumDef, VariantData}; use rustc_errors::Applicability; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; @@ -106,7 +106,7 @@ fn extract_default_variant<'a>( let default_variants: SmallVec<[_; 1]> = enum_def .variants .iter() - .filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default)) + .filter(|variant| attr::contains_name(&variant.attrs, kw::Default)) .collect(); let variant = match default_variants.as_slice() { @@ -116,7 +116,7 @@ fn extract_default_variant<'a>( .variants .iter() .filter(|variant| matches!(variant.data, VariantData::Unit(..))) - .filter(|variant| !cx.sess.contains_name(&variant.attrs, sym::non_exhaustive)); + .filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive)); let mut diag = cx.struct_span_err(trait_span, "no default declared"); diag.help("make a unit variant default by placing `#[default]` above it"); @@ -146,7 +146,7 @@ fn extract_default_variant<'a>( if v.span == variant.span { None } else { - Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new())) + Some((attr::find_by_name(&v.attrs, kw::Default)?.span, String::new())) } }) .collect(); @@ -174,7 +174,7 @@ fn extract_default_variant<'a>( return Err(()); } - if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) { + if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { cx.struct_span_err(variant.ident.span, "default variant must be exhaustive") .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here") .help("consider a manual implementation of `Default`") @@ -191,7 +191,7 @@ fn validate_default_attribute( default_variant: &rustc_ast::Variant, ) -> Result<(), ()> { let attrs: SmallVec<[_; 1]> = - cx.sess.filter_by_name(&default_variant.attrs, kw::Default).collect(); + attr::filter_by_name(&default_variant.attrs, kw::Default).collect(); let attr = match attrs.as_slice() { [attr] => attr, diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index bc513607ddd..378d5f39f4a 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, NodeId}; +use rustc_ast::{self as ast, attr, NodeId}; use rustc_ast_pretty::pprust; use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; @@ -34,7 +34,6 @@ enum ProcMacro { } struct CollectProcMacros<'a> { - sess: &'a Session, macros: Vec<ProcMacro>, in_root: bool, handler: &'a rustc_errors::Handler, @@ -44,19 +43,18 @@ struct CollectProcMacros<'a> { } pub fn inject( + krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand, - mut krate: ast::Crate, is_proc_macro_crate: bool, has_proc_macro_decls: bool, is_test_crate: bool, handler: &rustc_errors::Handler, -) -> ast::Crate { +) { let ecfg = ExpansionConfig::default("proc_macro".to_string()); let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); let mut collect = CollectProcMacros { - sess, macros: Vec::new(), in_root: true, handler, @@ -66,22 +64,20 @@ pub fn inject( }; if has_proc_macro_decls || is_proc_macro_crate { - visit::walk_crate(&mut collect, &krate); + visit::walk_crate(&mut collect, krate); } let macros = collect.macros; if !is_proc_macro_crate { - return krate; + return; } if is_test_crate { - return krate; + return; } let decls = mk_decls(&mut cx, ¯os); krate.items.push(decls); - - krate } impl<'a> CollectProcMacros<'a> { @@ -160,7 +156,7 @@ impl<'a> CollectProcMacros<'a> { impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { if let ast::ItemKind::MacroDef(..) = item.kind { - if self.is_proc_macro_crate && self.sess.contains_name(&item.attrs, sym::macro_export) { + if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { let msg = "cannot export macro_rules! macros from a `proc-macro` crate type currently"; self.handler.span_err(self.source_map.guess_head_span(item.span), msg); @@ -176,7 +172,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { let mut found_attr: Option<&'a ast::Attribute> = None; for attr in &item.attrs { - if self.sess.is_proc_macro_attr(&attr) { + if attr.is_proc_macro_attr() { if let Some(prev_attr) = found_attr { let prev_item = prev_attr.get_normal_item(); let item = attr.get_normal_item(); diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e67c0dba685..6493c6f13d5 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -1,4 +1,4 @@ -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::ExpansionConfig; use rustc_session::Session; @@ -9,17 +9,19 @@ use rustc_span::DUMMY_SP; use thin_vec::thin_vec; pub fn inject( - mut krate: ast::Crate, + krate: &mut ast::Crate, + pre_configured_attrs: &[ast::Attribute], resolver: &mut dyn ResolverExpand, sess: &Session, -) -> ast::Crate { +) -> usize { + let orig_num_items = krate.items.len(); let edition = sess.parse_sess.edition; // the first name in this list is the crate name of the crate with the prelude - let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) { - return krate; - } else if sess.contains_name(&krate.attrs, sym::no_std) { - if sess.contains_name(&krate.attrs, sym::compiler_builtins) { + let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) { + return 0; + } else if attr::contains_name(pre_configured_attrs, sym::no_std) { + if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) { &[sym::core] } else { &[sym::core, sym::compiler_builtins] @@ -88,6 +90,5 @@ pub fn inject( ); krate.items.insert(0, use_item); - - krate + krate.items.len() - orig_num_items } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index e02c7e6c01b..44b9c4718a7 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -1,14 +1,13 @@ /// The expansion from a test function to the appropriate test struct for libtest /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; -use rustc_ast as ast; use rustc_ast::ptr::P; +use rustc_ast::{self as ast, attr}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_expand::base::*; -use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{FileNameDisplayPreference, Span}; use std::iter; use thin_vec::{thin_vec, ThinVec}; @@ -33,7 +32,23 @@ pub fn expand_test_case( } let sp = ecx.with_def_site_ctxt(attr_sp); - let mut item = anno_item.expect_item(); + let (mut item, is_stmt) = match anno_item { + Annotatable::Item(item) => (item, false), + Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => if let ast::StmtKind::Item(i) = stmt.into_inner().kind { + (i, true) + } else { + unreachable!() + }, + _ => { + ecx.struct_span_err( + anno_item.span(), + "`#[test_case]` attribute is only allowed on items", + ) + .emit(); + + return vec![]; + } + }; item = item.map(|mut item| { let test_path_symbol = Symbol::intern(&item_path( // skip the name of the root module @@ -50,7 +65,13 @@ pub fn expand_test_case( item }); - return vec![Annotatable::Item(item)]; + let ret = if is_stmt { + Annotatable::Stmt(P(ecx.stmt_item(item.span, item))) + } else { + Annotatable::Item(item) + }; + + vec![ret] } pub fn expand_test( @@ -231,6 +252,8 @@ pub fn expand_test_or_bench( &item.ident, )); + let location_info = get_location_info(cx, &item); + let mut test_const = cx.item( sp, Ident::new(item.ident.name, sp), @@ -267,19 +290,26 @@ pub fn expand_test_or_bench( ), ), // ignore: true | false - field( - "ignore", - cx.expr_bool(sp, should_ignore(&cx.sess, &item)), - ), + field("ignore", cx.expr_bool(sp, should_ignore(&item)),), // ignore_message: Some("...") | None field( "ignore_message", - if let Some(msg) = should_ignore_message(cx, &item) { + if let Some(msg) = should_ignore_message(&item) { cx.expr_some(sp, cx.expr_str(sp, msg)) } else { cx.expr_none(sp) }, ), + // source_file: <relative_path_of_source_file> + field("source_file", cx.expr_str(sp, location_info.0)), + // start_line: start line of the test fn identifier. + field("start_line", cx.expr_usize(sp, location_info.1)), + // start_col: start column of the test fn identifier. + field("start_col", cx.expr_usize(sp, location_info.2)), + // end_line: end line of the test fn identifier. + field("end_line", cx.expr_usize(sp, location_info.3)), + // end_col: end column of the test fn identifier. + field("end_col", cx.expr_usize(sp, location_info.4)), // compile_fail: true | false field("compile_fail", cx.expr_bool(sp, false)), // no_run: true | false @@ -364,6 +394,19 @@ pub fn expand_test_or_bench( } } +fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) { + let span = item.ident.span; + let (source_file, lo_line, lo_col, hi_line, hi_col) = + cx.sess.source_map().span_to_location_info(span); + + let file_name = match source_file { + Some(sf) => sf.name.display(FileNameDisplayPreference::Remapped).to_string(), + None => "no-location".to_string(), + }; + + (Symbol::intern(&file_name), lo_line, lo_col, hi_line, hi_col) +} + fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String { mod_path .iter() @@ -378,12 +421,12 @@ enum ShouldPanic { Yes(Option<Symbol>), } -fn should_ignore(sess: &Session, i: &ast::Item) -> bool { - sess.contains_name(&i.attrs, sym::ignore) +fn should_ignore(i: &ast::Item) -> bool { + attr::contains_name(&i.attrs, sym::ignore) } -fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> { - match cx.sess.find_by_name(&i.attrs, sym::ignore) { +fn should_ignore_message(i: &ast::Item) -> Option<Symbol> { + match attr::find_by_name(&i.attrs, sym::ignore) { Some(attr) => { match attr.meta_item_list() { // Handle #[ignore(bar = "foo")] @@ -397,7 +440,7 @@ fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> { } fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { - match cx.sess.find_by_name(&i.attrs, sym::should_panic) { + match attr::find_by_name(&i.attrs, sym::should_panic) { Some(attr) => { let sd = &cx.sess.parse_sess.span_diagnostic; @@ -463,7 +506,7 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType { } fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { - let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic); + let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); let sd = &cx.sess.parse_sess.span_diagnostic; match &i.kind { ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index d8e3db9e8ee..43ab6c04428 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> { /// Traverse the crate, collecting all the test functions, eliding any /// existing main functions, and synthesizing a main test harness -pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) { +pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand) { let span_diagnostic = sess.diagnostic(); let panic_strategy = sess.panic_strategy(); let platform_panic_strategy = sess.target.panic_strategy; @@ -47,11 +47,11 @@ pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast // unconditional, so that the attribute is still marked as used in // non-test builds. let reexport_test_harness_main = - sess.first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main); + attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main); // Do this here so that the test_runner crate attribute gets marked as used // even in non-test builds - let test_runner = get_test_runner(sess, span_diagnostic, &krate); + let test_runner = get_test_runner(span_diagnostic, &krate); if sess.opts.test { let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) { @@ -123,7 +123,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { let mut item = i.into_inner(); - if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) { + if let Some(name) = get_test_name(&item) { debug!("this is a test item"); let test = Test { span: item.span, ident: item.ident, name }; @@ -145,12 +145,12 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { // Beware, this is duplicated in librustc_passes/entry.rs (with // `rustc_hir::Item`), so make sure to keep them in sync. -fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPointType { +fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType { match item.kind { ast::ItemKind::Fn(..) => { - if sess.contains_name(&item.attrs, sym::start) { + if attr::contains_name(&item.attrs, sym::start) { EntryPointType::Start - } else if sess.contains_name(&item.attrs, sym::rustc_main) { + } else if attr::contains_name(&item.attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else if item.ident.name == sym::main { if depth == 0 { @@ -184,7 +184,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { // Remove any #[rustc_main] or #[start] from the AST so it doesn't // clash with the one we're going to add, but mark it as // #[allow(dead_code)] to avoid printing warnings. - let item = match entry_point_type(self.sess, &item, self.depth) { + let item = match entry_point_type(&item, self.depth) { EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| { let allow_dead_code = attr::mk_attr_nested_word( @@ -373,16 +373,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> { ) } -fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> { - sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) +fn get_test_name(i: &ast::Item) -> Option<Symbol> { + attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) } -fn get_test_runner( - sess: &Session, - sd: &rustc_errors::Handler, - krate: &ast::Crate, -) -> Option<ast::Path> { - let test_attr = sess.find_by_name(&krate.attrs, sym::test_runner)?; +fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> { + let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?; let meta_list = test_attr.meta_item_list()?; let span = test_attr.span; match &*meta_list { diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 83812631c2f..9463a1418ce 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,4 +1,4 @@ -use rustc_ast::{AttrStyle, Attribute, MetaItem}; +use rustc_ast::{attr, AttrStyle, Attribute, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_feature::AttributeTemplate; use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; @@ -36,7 +36,7 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: _ => None, }; if let Some(attrs) = attrs { - if let Some(attr) = ecx.sess.find_by_name(attrs, name) { + if let Some(attr) = attr::find_by_name(attrs, name) { ecx.parse_sess().buffer_lint( DUPLICATE_MACRO_ATTRIBUTES, attr.span, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index d0af3729b23..2107ae147e9 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -346,17 +346,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { crate::abi::codegen_return(fx); } TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => { - if !fx.tcx.sess.overflow_checks() { - let overflow_not_to_check = match msg { - AssertKind::OverflowNeg(..) => true, - AssertKind::Overflow(op, ..) => op.is_checkable(), - _ => false, - }; - if overflow_not_to_check { - let target = fx.get_block(*target); - fx.bcx.ins().jump(target, &[]); - continue; - } + if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() { + let target = fx.get_block(*target); + fx.bcx.ins().jump(target, &[]); + continue; } let cond = codegen_operand(fx, cond).load_scalar(fx); @@ -716,6 +709,10 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); operand.coerce_dyn_star(fx, lval); } + Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => { + let operand = codegen_operand(fx, operand); + lval.write_cvalue_transmute(fx, operand); + } Rvalue::Discriminant(place) => { let place = codegen_place(fx, place); let value = place.to_cvalue(fx); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index fe48cac4faf..03f2a65fcca 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -557,16 +557,6 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().band(ptr, mask); } - sym::transmute => { - intrinsic_args!(fx, args => (from); intrinsic); - - if ret.layout().abi.is_uninhabited() { - crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info); - return; - } - - ret.write_cvalue_transmute(fx, from); - } sym::write_bytes | sym::volatile_set_memory => { intrinsic_args!(fx, args => (dst, val, count); intrinsic); let val = val.load_scalar(fx); diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index b7bfd8fd395..94806e0d798 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -48,9 +48,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( ) -> (Pointer, Value) { let (ptr, vtable) = 'block: { if let Abi::Scalar(_) = arg.layout().abi { - 'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() - && !arg.layout().ty.is_region_ptr() - { + 'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { for i in 0..arg.layout().fields.count() { let field = arg.value_field(fx, mir::Field::new(i)); if !field.layout().is_zst() { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 76fc7bd222e..ac04b61a306 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -73,6 +73,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } + fn const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc> { + // No distinction between undef and poison. + self.const_undef(typ) + } + fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { self.gcc_int(typ, int) } diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index dd3268d7780..a570f2af0f0 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -189,6 +189,15 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { path.push(lib_name); path }; + // dlltool target architecture args from: + // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69 + let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() { + "x86_64" => ("i386:x86-64", "--64"), + "x86" => ("i386", "--32"), + "aarch64" => ("arm64", "--64"), + "arm" => ("arm", "--32"), + _ => panic!("unsupported arch {}", sess.target.arch), + }; let result = std::process::Command::new(dlltool) .args([ "-d", @@ -197,6 +206,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { lib_name, "-l", output_path.to_str().unwrap(), + "-m", + dlltool_target_arch, + "-f", + dlltool_target_bitness, "--no-leading-underscore", "--temp-prefix", temp_prefix.to_str().unwrap(), @@ -422,24 +435,22 @@ fn find_binutils_dlltool(sess: &Session) -> OsString { return dlltool_path.clone().into_os_string(); } - let mut tool_name: OsString = if sess.host.arch != sess.target.arch { - // We are cross-compiling, so we need the tool with the prefix matching our target - if sess.target.arch == "x86" { - "i686-w64-mingw32-dlltool" - } else { - "x86_64-w64-mingw32-dlltool" - } + let tool_name: OsString = if sess.host.options.is_like_windows { + // If we're compiling on Windows, always use "dlltool.exe". + "dlltool.exe" } else { - // We are not cross-compiling, so we just want `dlltool` - "dlltool" + // On other platforms, use the architecture-specific name. + match sess.target.arch.as_ref() { + "x86_64" => "x86_64-w64-mingw32-dlltool", + "x86" => "i686-w64-mingw32-dlltool", + "aarch64" => "aarch64-w64-mingw32-dlltool", + + // For non-standard architectures (e.g., aarch32) fallback to "dlltool". + _ => "dlltool", + } } .into(); - if sess.host.options.is_like_windows { - // If we're compiling on Windows, add the .exe suffix - tool_name.push(".exe"); - } - // NOTE: it's not clear how useful it is to explicitly search PATH. for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let full_path = dir.join(&tool_name); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 0f33b985489..580451ba265 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -990,7 +990,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) { let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false); - let mut exn = self.const_undef(ty); + let mut exn = self.const_poison(ty); exn = self.insert_value(exn, exn0, 0); exn = self.insert_value(exn, exn1, 1); unsafe { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b0a9a30ab46..efa0c13226e 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -130,6 +130,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMGetUndef(t) } } + fn const_poison(&self, t: &'ll Type) -> &'ll Value { + unsafe { llvm::LLVMGetPoison(t) } + } + fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value { unsafe { llvm::LLVMConstInt(t, i as u64, True) } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 80fd9726fc7..ff2b005d757 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -5,12 +5,12 @@ use crate::llvm; use crate::builder::Builder; use crate::common::CodegenCx; use crate::value::Value; +use rustc_ast::attr; use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_session::config::{CrateType, DebugInfo}; - use rustc_span::symbol::sym; use rustc_span::DebuggerVisualizerType; @@ -87,7 +87,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { let omit_gdb_pretty_printer_section = - cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); + attr::contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create // ODR violations at link time, this section will not be emitted for rlibs since diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 9c921989ca9..012e25884ca 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -378,7 +378,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } - _ => bug!("unknown intrinsic '{}'", name), + _ => bug!("unknown intrinsic '{}' -- should it have been lowered earlier?", name), }; if !fn_abi.ret.is_ignore() { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8dafe1b750b..e5bae009ed6 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -361,12 +361,12 @@ impl CodegenBackend for LlvmCodegenBackend { .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>") .join(sess); - sess.time("llvm_dump_timing_file", || { - if sess.opts.unstable_opts.llvm_time_trace { + if sess.opts.unstable_opts.llvm_time_trace { + sess.time("llvm_dump_timing_file", || { let file_name = outputs.with_extension("llvm_timings.json"); llvm_util::time_trace_profiler_finish(&file_name); - } - }); + }); + } Ok((codegen_results, work_products)) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 509cb0fef56..9e5265188b5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1069,6 +1069,7 @@ extern "C" { // Operations on constants of any type pub fn LLVMConstNull(Ty: &Type) -> &Value; pub fn LLVMGetUndef(Ty: &Type) -> &Value; + pub fn LLVMGetPoison(Ty: &Type) -> &Value; // Operations on metadata pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value; diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ba58a2e68e9..46692fd5e8b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -424,7 +424,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str .filter_map(|s| { let enable_disable = match s.chars().next() { None => return None, - Some(c @ '+' | c @ '-') => c, + Some(c @ ('+' | '-')) => c, Some(_) => { if diagnostics { sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s }); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8aa744ce935..6a0d0ca55c2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -358,9 +358,9 @@ fn link_rlib<'a>( let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src); let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str()); packed_bundled_libs.push(wrapper_file); - } else if let Some(name) = lib.name { + } else { let path = - find_native_static_library(name.as_str(), lib.verbatim, &lib_search_paths, sess); + find_native_static_library(lib.name.as_str(), lib.verbatim, &lib_search_paths, sess); ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| { sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })}); } @@ -436,7 +436,7 @@ fn collate_raw_dylibs<'a, 'b>( for lib in used_libraries { if lib.kind == NativeLibKind::RawDylib { let ext = if lib.verbatim { "" } else { ".dll" }; - let name = format!("{}{}", lib.name.expect("unnamed raw-dylib library"), ext); + let name = format!("{}{}", lib.name, ext); let imports = dylib_table.entry(name.clone()).or_default(); for import in &lib.dll_imports { if let Some(old_import) = imports.insert(import.name, import) { @@ -1199,7 +1199,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs)) .unwrap_or(stem); - // GCC can have an optional target prefix. + // GCC/Clang can have an optional target prefix. let flavor = if stem == "emcc" { LinkerFlavor::EmCc } else if stem == "gcc" @@ -1207,7 +1207,9 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { || stem == "g++" || stem.ends_with("-g++") || stem == "clang" + || stem.ends_with("-clang") || stem == "clang++" + || stem.ends_with("-clang++") { LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target) } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") { @@ -1294,7 +1296,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { .iter() .filter(|l| relevant_lib(sess, l)) .filter_map(|lib| { - let name = lib.name?; + let name = lib.name; match lib.kind { NativeLibKind::Static { bundle: Some(false), .. } | NativeLibKind::Dylib { .. } @@ -1315,6 +1317,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { // These are included, no need to print them NativeLibKind::Static { bundle: None | Some(true), .. } | NativeLibKind::LinkArg + | NativeLibKind::WasmImportModule | NativeLibKind::RawDylib => None, } }) @@ -2273,21 +2276,18 @@ fn add_native_libs_from_crate( let mut last = (None, NativeLibKind::Unspecified, false); for lib in native_libs { - let Some(name) = lib.name else { - continue; - }; if !relevant_lib(sess, lib) { continue; } // Skip if this library is the same as the last. - last = if (lib.name, lib.kind, lib.verbatim) == last { + last = if (Some(lib.name), lib.kind, lib.verbatim) == last { continue; } else { - (lib.name, lib.kind, lib.verbatim) + (Some(lib.name), lib.kind, lib.verbatim) }; - let name = name.as_str(); + let name = lib.name.as_str(); let verbatim = lib.verbatim; match lib.kind { NativeLibKind::Static { bundle, whole_archive } => { @@ -2344,6 +2344,7 @@ fn add_native_libs_from_crate( NativeLibKind::RawDylib => { // Handled separately in `linker_with_args`. } + NativeLibKind::WasmImportModule => {} NativeLibKind::LinkArg => { if link_static { cmd.arg(name); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 23e2b272410..dd117681950 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -133,6 +133,9 @@ pub fn get_linker<'a>( LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => { Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker> } + LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => { + Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker> + } LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>, LinkerFlavor::Gnu(cc, _) | LinkerFlavor::Darwin(cc, _) @@ -1474,6 +1477,177 @@ impl<'a> L4Bender<'a> { } } +/// Linker for AIX. +pub struct AixLinker<'a> { + cmd: Command, + sess: &'a Session, + hinted_static: bool, +} + +impl<'a> AixLinker<'a> { + pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { + AixLinker { cmd: cmd, sess: sess, hinted_static: false } + } + + fn hint_static(&mut self) { + if !self.hinted_static { + self.cmd.arg("-bstatic"); + self.hinted_static = true; + } + } + + fn hint_dynamic(&mut self) { + if self.hinted_static { + self.cmd.arg("-bdynamic"); + self.hinted_static = false; + } + } + + fn build_dylib(&mut self, _out_filename: &Path) { + self.cmd.arg("-bM:SRE"); + self.cmd.arg("-bnoentry"); + // FIXME: Use CreateExportList utility to create export list + // and remove -bexpfull. + self.cmd.arg("-bexpfull"); + } +} + +impl<'a> Linker for AixLinker<'a> { + fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) { + self.hint_dynamic(); + self.cmd.arg(format!("-l{}", lib)); + } + + fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { + self.hint_static(); + self.cmd.arg(format!("-l{}", lib)); + } + + fn link_rlib(&mut self, lib: &Path) { + self.hint_static(); + self.cmd.arg(lib); + } + + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + + fn framework_path(&mut self, _: &Path) { + bug!("frameworks are not supported on AIX"); + } + + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn full_relro(&mut self) {} + + fn partial_relro(&mut self) {} + + fn no_relro(&mut self) {} + + fn cmd(&mut self) -> &mut Command { + &mut self.cmd + } + + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicDylib => { + self.hint_dynamic(); + self.build_dylib(out_filename); + } + LinkOutputKind::StaticDylib => { + self.hint_static(); + self.build_dylib(out_filename); + } + _ => {} + } + } + + fn link_rust_dylib(&mut self, lib: &str, _: &Path) { + self.hint_dynamic(); + self.cmd.arg(format!("-l{}", lib)); + } + + fn link_framework(&mut self, _framework: &str, _as_needed: bool) { + bug!("frameworks not supported on AIX"); + } + + fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { + self.hint_static(); + let lib = find_native_static_library(lib, verbatim, search_path, &self.sess); + self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); + } + + fn link_whole_rlib(&mut self, lib: &Path) { + self.hint_static(); + self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); + } + + fn gc_sections(&mut self, _keep_metadata: bool) { + self.cmd.arg("-bgc"); + } + + fn no_gc_sections(&mut self) { + self.cmd.arg("-bnogc"); + } + + fn optimize(&mut self) {} + + fn pgo_gen(&mut self) {} + + fn control_flow_guard(&mut self) {} + + fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { + match strip { + Strip::None => {} + // FIXME: -s strips the symbol table, line number information + // and relocation information. + Strip::Debuginfo | Strip::Symbols => { + self.cmd.arg("-s"); + } + } + } + + fn no_crt_objects(&mut self) {} + + fn no_default_libraries(&mut self) {} + + fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + let path = tmpdir.join("list.exp"); + let res: io::Result<()> = try { + let mut f = BufWriter::new(File::create(&path)?); + // TODO: use llvm-nm to generate export list. + for symbol in symbols { + debug!(" _{}", symbol); + writeln!(f, " {}", symbol)?; + } + }; + if let Err(e) = res { + self.sess.fatal(&format!("failed to write export file: {}", e)); + } + self.cmd.arg(format!("-bE:{}", path.to_str().unwrap())); + } + + fn subsystem(&mut self, _subsystem: &str) {} + + fn reset_per_library_state(&mut self) { + self.hint_dynamic(); + } + + fn linker_plugin_lto(&mut self) {} + + fn add_eh_frame_header(&mut self) {} + + fn add_no_exec(&mut self) {} + + fn add_as_needed(&mut self) {} +} + fn for_each_exported_symbols_include_dep<'tcx>( tcx: TyCtxt<'tcx>, crate_type: CrateType, diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 7b58e55dbe8..e403a1fd8ae 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -10,6 +10,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; @@ -41,9 +42,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel { } } -fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<SymbolExportInfo> { - assert_eq!(cnum, LOCAL_CRATE); - +fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<SymbolExportInfo> { if !tcx.sess.opts.output_types.should_codegen() { return Default::default(); } @@ -154,10 +153,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< reachable_non_generics } -fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: DefId) -> bool { +fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let export_threshold = threshold(tcx); - if let Some(&info) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { + if let Some(&info) = tcx.reachable_non_generics(LOCAL_CRATE).get(&def_id.to_def_id()) { info.level.is_below_threshold(export_threshold) } else { false @@ -170,10 +169,8 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b fn exported_symbols_provider_local( tcx: TyCtxt<'_>, - cnum: CrateNum, + _: LocalCrate, ) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] { - assert_eq!(cnum, LOCAL_CRATE); - if !tcx.sess.opts.output_types.should_codegen() { return &[]; } @@ -595,7 +592,7 @@ fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, S let mut ret = FxHashMap::default(); for (def_id, lib) in tcx.foreign_modules(cnum).iter() { - let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module); + let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module()); let Some(module) = module else { continue }; ret.extend(lib.foreign_items.iter().map(|id| { assert_eq!(id.krate, cnum); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 8508ab87532..7ce72d21727 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -8,6 +8,7 @@ use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, }; use jobserver::{Acquired, Client}; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; @@ -447,8 +448,8 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( let sess = tcx.sess; let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins); - let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins); + let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); + let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins); let crate_info = CrateInfo::new(tcx, target_cpu); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index abc510e360d..c3c8649dbff 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -786,6 +786,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( total_codegen_time, start_rss.unwrap(), end_rss, + tcx.sess.opts.unstable_opts.time_passes_format, ); } @@ -809,7 +810,7 @@ impl CrateInfo { .collect(); let local_crate_name = tcx.crate_name(LOCAL_CRATE); let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); + let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); let windows_subsystem = subsystem.map(|subsystem| { if subsystem != sym::windows && subsystem != sym::console { tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem }); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index f9bb8359208..037b07dec62 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -43,7 +43,7 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { } } -fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { +fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if cfg!(debug_assertions) { let def_kind = tcx.def_kind(did); assert!( @@ -52,7 +52,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { ); } - let did = did.expect_local(); let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did)); let mut codegen_fn_attrs = CodegenFnAttrs::new(); if tcx.should_inherit_track_caller(did) { diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs index 0f6e6032f9b..c34f1dbf856 100644 --- a/compiler/rustc_codegen_ssa/src/glue.rs +++ b/compiler/rustc_codegen_ssa/src/glue.rs @@ -46,7 +46,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // NOTE: ideally, we want the effects of both `unchecked_smul` and `unchecked_umul` // (resulting in `mul nsw nuw` in LLVM IR), since we know that the multiplication // cannot signed wrap, and that both operands are non-negative. But at the time of writing, - // `BuilderMethods` can't do this, and it doesn't seem to enable any further optimizations. + // the `LLVM-C` binding can't do this, and it doesn't seem to enable any further optimizations. bx.unchecked_smul(info.unwrap(), bx.const_usize(unit.size.bytes())), bx.const_usize(unit.align.abi.bytes()), ) diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 8e721a84eaf..81227b04e8a 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -118,7 +118,7 @@ bitflags::bitflags! { #[derive(Clone, Debug, Encodable, Decodable, HashStable)] pub struct NativeLib { pub kind: NativeLibKind, - pub name: Option<Symbol>, + pub name: Symbol, pub filename: Option<Symbol>, pub cfg: Option<ast::MetaItem>, pub verbatim: bool, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 71c71d59b7a..5da0e826c56 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -16,7 +16,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Instance, Ty}; use rustc_session::config::OptLevel; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; @@ -563,15 +563,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // with #[rustc_inherit_overflow_checks] and inlined from // another crate (mostly core::num generic/#[inline] fns), // while the current crate doesn't use overflow checks. - if !bx.cx().check_overflow() { - let overflow_not_to_check = match msg { - AssertKind::OverflowNeg(..) => true, - AssertKind::Overflow(op, ..) => op.is_checkable(), - _ => false, - }; - if overflow_not_to_check { - const_cond = Some(expected); - } + if !bx.cx().check_overflow() && msg.is_optional_overflow_check() { + const_cond = Some(expected); } // Don't codegen the panic block if success if known. @@ -776,23 +769,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => bx.fn_abi_of_fn_ptr(sig, extra_args), }; - if intrinsic == Some(sym::transmute) { - return if let Some(target) = target { - self.codegen_transmute(bx, &args[0], destination); - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - // If we are trying to transmute to an uninhabited type, - // it is likely there is no allotted destination. In fact, - // transmuting to an uninhabited type is UB, which means - // we can do what we like. Here, we declare that transmuting - // into an uninhabited type is impossible, so anything following - // it must be unreachable. - assert_eq!(fn_abi.ret.layout.abi, abi::Abi::Uninhabited); - bx.unreachable(); - MergingSucc::False - }; - } - if let Some(merging_succ) = self.codegen_panic_intrinsic( &helper, bx, @@ -835,7 +811,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match intrinsic { None | Some(sym::drop_in_place) => {} - Some(sym::copy_nonoverlapping) => unreachable!(), Some(intrinsic) => { let dest = match ret_dest { _ if fn_abi.ret.is_indirect() => llargs[0], @@ -924,7 +899,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`. 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_region_ptr() + && !op.layout.ty.is_ref() { for i in 0..op.layout.fields.count() { let field = op.extract_field(bx, i); @@ -966,7 +941,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Immediate(_) => { // See comment above explaining why we peel these newtypes 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_region_ptr() + && !op.layout.ty.is_ref() { for i in 0..op.layout.fields.count() { let field = op.extract_field(bx, i); @@ -1482,7 +1457,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> OperandRef<'tcx, Bx::Value> { let tcx = bx.tcx(); - let mut span_to_caller_location = |span: Span| { + let mut span_to_caller_location = |mut span: Span| { + // Remove `Inlined` marks as they pollute `expansion_cause`. + while span.is_inlined() { + span.remove_mark(); + } let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo()); let const_loc = tcx.const_caller_location(( @@ -1742,71 +1721,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn codegen_transmute(&mut self, bx: &mut Bx, src: &mir::Operand<'tcx>, dst: mir::Place<'tcx>) { - if let Some(index) = dst.as_local() { - match self.locals[index] { - LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), - LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), - LocalRef::Operand(None) => { - let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref())); - assert!(!dst_layout.ty.has_erasable_regions()); - let place = PlaceRef::alloca(bx, dst_layout); - place.storage_live(bx); - self.codegen_transmute_into(bx, src, place); - let op = bx.load_operand(place); - place.storage_dead(bx); - self.locals[index] = LocalRef::Operand(Some(op)); - self.debug_introduce_local(bx, index); - } - LocalRef::Operand(Some(op)) => { - assert!(op.layout.is_zst(), "assigning to initialized SSAtemp"); - } - } - } else { - let dst = self.codegen_place(bx, dst.as_ref()); - self.codegen_transmute_into(bx, src, dst); - } - } - - fn codegen_transmute_into( - &mut self, - bx: &mut Bx, - src: &mir::Operand<'tcx>, - dst: PlaceRef<'tcx, Bx::Value>, - ) { - let src = self.codegen_operand(bx, src); - - // Special-case transmutes between scalars as simple bitcasts. - match (src.layout.abi, dst.layout.abi) { - (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => { - // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers. - let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_)); - let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_)); - if src_is_ptr == dst_is_ptr { - assert_eq!(src.layout.size, dst.layout.size); - - // NOTE(eddyb) the `from_immediate` and `to_immediate_scalar` - // conversions allow handling `bool`s the same as `u8`s. - let src = bx.from_immediate(src.immediate()); - // LLVM also doesn't like `bitcast`s between pointers in different address spaces. - let src_as_dst = if src_is_ptr { - bx.pointercast(src, bx.backend_type(dst.layout)) - } else { - bx.bitcast(src, bx.backend_type(dst.layout)) - }; - Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst); - return; - } - } - _ => {} - } - - let llty = bx.backend_type(src.layout); - let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); - let align = src.layout.align.abi.min(dst.align); - src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, align)); - } - // Stores the return value of a function call into it's final location. fn store_return( &mut self, diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 708f3bc0c78..6e32c28a42c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -241,12 +241,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; - // FIXME(eddyb) maybe name the return place as `_0` or `return`? - if local == mir::RETURN_PLACE && !self.mir.local_decls[mir::RETURN_PLACE].is_user_variable() - { - return; - } - let vars = match &self.per_local_var_debug_info { Some(per_local) => &per_local[local], None => return, @@ -303,7 +297,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let local_ref = &self.locals[local]; - let name = if bx.sess().fewer_names() { + // FIXME Should the return place be named? + let name = if bx.sess().fewer_names() || local == mir::RETURN_PLACE { None } else { Some(match whole_local_var.or(fallback_var.clone()) { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 34a5b638d7e..25721f75583 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -60,7 +60,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { ) -> OperandRef<'tcx, V> { assert!(layout.is_zst()); OperandRef { - val: OperandValue::Immediate(bx.const_undef(bx.immediate_backend_type(layout))), + val: OperandValue::Immediate(bx.const_poison(bx.immediate_backend_type(layout))), layout, } } @@ -145,7 +145,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let llty = bx.cx().backend_type(self.layout); debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty); // Reconstruct the immediate aggregate. - let mut llpair = bx.cx().const_undef(llty); + let mut llpair = bx.cx().const_poison(llty); let imm_a = bx.from_immediate(a); let imm_b = bx.from_immediate(b); llpair = bx.insert_value(llpair, imm_a, 0); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index cf02f59f67b..f6523a448e3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -214,7 +214,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let cast_to_size = cast_to_layout.layout.size(); let cast_to = bx.cx().immediate_backend_type(cast_to_layout); if self.layout.abi.is_uninhabited() { - return bx.cx().const_undef(cast_to); + return bx.cx().const_poison(cast_to); } let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { Variants::Single { index } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 13c4fa132d8..14f57b63e97 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{self, VariantIdx}; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "trace", skip(self, bx))] @@ -72,6 +72,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => { + let src = self.codegen_operand(bx, operand); + self.codegen_transmute(bx, src, dest); + } + mir::Rvalue::Repeat(ref elem, count) => { let cg_elem = self.codegen_operand(bx, elem); @@ -143,6 +148,52 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + fn codegen_transmute( + &mut self, + bx: &mut Bx, + src: OperandRef<'tcx, Bx::Value>, + dst: PlaceRef<'tcx, Bx::Value>, + ) { + // The MIR validator enforces no unsized transmutes. + debug_assert!(src.layout.is_sized()); + debug_assert!(dst.layout.is_sized()); + + if src.layout.size != dst.layout.size + || src.layout.abi == abi::Abi::Uninhabited + || dst.layout.abi == abi::Abi::Uninhabited + { + // In all of these cases it's UB to run this transmute, but that's + // known statically so might as well trap for it, rather than just + // making it unreachable. + bx.abort(); + return; + } + + let size_in_bytes = src.layout.size.bytes(); + if size_in_bytes == 0 { + // Nothing to write + return; + } + + match src.val { + OperandValue::Ref(src_llval, meta, src_align) => { + debug_assert_eq!(meta, None); + // For a place-to-place transmute, call `memcpy` directly so that + // both arguments get the best-available alignment information. + let bytes = bx.cx().const_usize(size_in_bytes); + let flags = MemFlags::empty(); + bx.memcpy(dst.llval, dst.align, src_llval, src_align, bytes, flags); + } + OperandValue::Immediate(_) | OperandValue::Pair(_, _) => { + // When we have immediate(s), the alignment of the source is irrelevant, + // so we can store them using the destination's alignment. + let llty = bx.backend_type(src.layout); + let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); + src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, dst.align)); + } + } + } + pub fn codegen_rvalue_unsized( &mut self, bx: &mut Bx, @@ -295,7 +346,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(bx.cx().is_backend_immediate(cast)); let ll_t_out = bx.cx().immediate_backend_type(cast); if operand.layout.abi.is_uninhabited() { - let val = OperandValue::Immediate(bx.cx().const_undef(ll_t_out)); + let val = OperandValue::Immediate(bx.cx().const_poison(ll_t_out)); return OperandRef { val, layout: cast }; } let r_t_in = @@ -344,6 +395,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; OperandValue::Immediate(newval) } + mir::CastKind::Transmute => { + bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand); + } }; OperandRef { val, layout: cast } } @@ -673,6 +727,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { match *rvalue { + mir::Rvalue::Cast(mir::CastKind::Transmute, ..) => + // FIXME: Now that transmute is an Rvalue, it would be nice if + // it could create `Immediate`s for scalars, where possible. + false, mir::Rvalue::Ref(..) | mir::Rvalue::CopyForDeref(..) | mir::Rvalue::AddressOf(..) | diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index fdc7a30e841..61906302779 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -8,6 +8,7 @@ pub trait ConstMethods<'tcx>: BackendTypes { // Constant constructors fn const_null(&self, t: Self::Type) -> Self::Value; fn const_undef(&self, t: Self::Type) -> Self::Value; + fn const_poison(&self, t: Self::Type) -> Self::Value; fn const_int(&self, t: Self::Type, i: i64) -> Self::Value; fn const_uint(&self, t: Self::Type, i: u64) -> Self::Value; fn const_uint_big(&self, t: Self::Type, u: u128) -> Self::Value; diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 6dcfdc14790..088a824fd8f 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -32,8 +32,7 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// it is a trait impl/function, return if it has a `const` modifier. If it is an intrinsic, /// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return /// `Constness::NotConst`. -fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { - let def_id = def_id.expect_local(); +fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { let node = tcx.hir().get_by_def_id(def_id); match node { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index a44f70ed059..350ce529ef5 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,7 +2,7 @@ use rustc_hir::def::DefKind; use rustc_hir::{LangItem, CRATE_HIR_ID}; use rustc_middle::mir; use rustc_middle::mir::interpret::PointerArithmetic; -use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::INVALID_ALIGNMENT; use std::borrow::Borrow; @@ -335,8 +335,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } #[inline(always)] - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited() } fn alignment_check_failed( diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index c14152a916a..163e3f86993 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -133,6 +133,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bug!() } } + + Transmute => { + assert!(src.layout.is_sized()); + assert!(dest.layout.is_sized()); + if src.layout.size != dest.layout.size { + throw_ub_format!( + "transmuting from {}-byte type to {}-byte type: `{}` -> `{}`", + src.layout.size.bytes(), + dest.layout.size.bytes(), + src.layout.ty, + dest.layout.ty, + ); + } + + self.copy_op(src, dest, /*allow_transmute*/ true)?; + } } Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a29cdade023..26fb041b455 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -127,7 +127,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // First handle intrinsics without return place. let ret = match ret { None => match intrinsic_name { - sym::transmute => throw_ub_format!("transmuting to uninhabited type"), sym::abort => M::abort(self, "the program aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), @@ -411,9 +410,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.exact_div(&val, &size, dest)?; } - sym::transmute => { - self.copy_op(&args[0], dest, /*allow_transmute*/ true)?; - } sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs index cf52299b7ba..76c8d0a975a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -111,7 +111,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { location } - pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { + pub(crate) fn location_triple_for_span(&self, mut span: Span) -> (Symbol, u32, u32) { + // Remove `Inlined` marks as they pollute `expansion_cause`. + while span.is_inlined() { + span.remove_mark(); + } let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); ( diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 92fa59aec6e..aca68dc454b 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -8,6 +8,7 @@ use std::hash::Hash; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_target::abi::{Align, Size}; @@ -145,8 +146,8 @@ pub trait Machine<'mir, 'tcx>: Sized { check: CheckAlignment, ) -> InterpResult<'tcx, ()>; - /// Whether to enforce the validity invariant - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether to enforce the validity invariant for a specific layout. + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool; /// Whether function calls should be [ABI](CallAbi)-checked. fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { @@ -155,7 +156,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether Assert(OverflowNeg) and Assert(Overflow) MIR terminators should actually /// check for overflow. - fn ignore_checkable_overflow_assertions(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + fn ignore_optional_overflow_checks(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; /// Entry point for obtaining the MIR of anything that should get evaluated. /// So not just functions and shims, but also const/static initializers, anonymous @@ -474,7 +475,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] - fn ignore_checkable_overflow_assertions(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + fn ignore_optional_overflow_checks(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { false } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 3c463500a60..ff6db143ddf 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -461,7 +461,7 @@ where ) -> InterpResult<'tcx> { self.write_immediate_no_validate(src, dest)?; - if M::enforce_validity(self) { + if M::enforce_validity(self, dest.layout) { // Data got changed, better make sure it matches the type! self.validate_operand(&self.place_to_op(dest)?)?; } @@ -616,7 +616,7 @@ where ) -> InterpResult<'tcx> { self.copy_op_no_validate(src, dest, allow_transmute)?; - if M::enforce_validity(self) { + if M::enforce_validity(self, dest.layout) { // Data got changed, better make sure it matches the type! self.validate_operand(&self.place_to_op(dest)?)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 685a5599cde..c2d1bc11c37 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -138,12 +138,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Assert { ref cond, expected, ref msg, target, cleanup } => { - let ignored = M::ignore_checkable_overflow_assertions(self) - && match msg { - mir::AssertKind::OverflowNeg(..) => true, - mir::AssertKind::Overflow(op, ..) => op.is_checkable(), - _ => false, - }; + let ignored = + M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check(); let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?; if ignored || expected == cond_val { self.go_to_block(target); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index db55dbc2bfd..0d9cd78fe12 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -246,7 +246,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); } - if !tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) { + if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) { self.visit_body(&body); } @@ -643,7 +643,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if base_ty.is_unsafe_ptr() { if proj_base.is_empty() { let decl = &self.body.local_decls[place_local]; - if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { + if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() { let span = decl.source_info.span; self.check_static(def_id, span); return; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index e586720a0d0..c0f5b3725b3 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -704,7 +704,7 @@ pub mod ty { fn importance(&self) -> DiagnosticImportance { match self.0 { - mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::Temp => DiagnosticImportance::Secondary, mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { DiagnosticImportance::Primary } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs index 43806035a44..f01ab4c5d61 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs @@ -30,7 +30,7 @@ pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { return; } - if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) { + if tcx.has_attr(def_id, sym::rustc_do_not_const_check) { return; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index bb4b7ad50b8..6758cba2eed 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -9,7 +9,7 @@ use rustc_middle::mir; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_trait_selection::traits::{ - self, ImplSource, Obligation, ObligationCause, SelectionContext, + self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, }; use super::ConstCx; @@ -184,7 +184,10 @@ impl Qualif for NeedsNonConstDrop { } // If we had any errors, then it's bad - !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty() + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligations(impl_src.nested_obligations()); + let errors = ocx.select_all_or_error(); + !errors.is_empty() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 3f3b66b0645..648a86d32fc 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -106,8 +106,9 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); // We're only interested in temporaries and the return place match self.ccx.body.local_kind(index) { - LocalKind::Temp | LocalKind::ReturnPointer => {} - LocalKind::Arg | LocalKind::Var => return, + LocalKind::Arg => return, + LocalKind::Temp if self.ccx.body.local_decls[index].is_user_variable() => return, + LocalKind::ReturnPointer | LocalKind::Temp => {} } // Ignore drops, if the temp gets promoted, diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index e0939d1d1ba..66fc1c07e20 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -621,6 +621,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + CastKind::Transmute => { + if let MirPhase::Runtime(..) = self.mir_phase { + // Unlike `mem::transmute`, a MIR `Transmute` is well-formed + // for any two `Sized` types, just potentially UB to run. + + if !op_ty.is_sized(self.tcx, self.param_env) { + self.fail( + location, + format!("Cannot transmute from non-`Sized` type {op_ty:?}"), + ); + } + if !target_type.is_sized(self.tcx, self.param_env) { + self.fail( + location, + format!("Cannot transmute to non-`Sized` type {target_type:?}"), + ); + } + } else { + self.fail( + location, + format!( + "Transmute is not supported in non-runtime phase {:?}.", + self.mir_phase + ), + ); + } + } } } Rvalue::Repeat(_, _) diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 29cb2c0a33e..056ee1f63be 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" arrayvec = { version = "0.7", default-features = false } bitflags = "1.2.1" cfg-if = "1.0" -ena = "0.14.1" +ena = "0.14.2" indexmap = { version = "1.9.1" } jobserver_crate = { version = "0.1.13", package = "jobserver" } libc = "0.2" @@ -21,6 +21,7 @@ rustc-hash = "1.1.0" rustc_index = { path = "../rustc_index", package = "rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } +serde_json = "1.0.59" smallvec = { version = "1.8.1", features = [ "const_generics", "union", @@ -36,8 +37,15 @@ elsa = "1.8" [dependencies.parking_lot] version = "0.11" -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] } +[target.'cfg(windows)'.dependencies.windows] +version = "0.46.0" +features = [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_System_IO", + "Win32_System_ProcessStatus", + "Win32_System_Threading", +] [target.'cfg(not(target_arch = "wasm32"))'.dependencies] memmap2 = "0.2.1" diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index e395d8dbbbf..efdb44248d1 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -4,9 +4,6 @@ //! green/native threading. This is just a bare-bones enough solution for //! librustdoc, it is not production quality at all. -#![allow(non_camel_case_types)] -#![allow(nonstandard_style)] - cfg_if! { if #[cfg(target_os = "linux")] { mod linux; @@ -16,7 +13,7 @@ cfg_if! { use unix as imp; } else if #[cfg(windows)] { mod windows; - use windows as imp; + use self::windows as imp; } else { mod unsupported; use unsupported as imp; diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs index 43e6caaa18d..da128f464a6 100644 --- a/compiler/rustc_data_structures/src/flock/windows.rs +++ b/compiler/rustc_data_structures/src/flock/windows.rs @@ -1,13 +1,16 @@ use std::fs::{File, OpenOptions}; use std::io; -use std::mem; use std::os::windows::prelude::*; use std::path::Path; -use winapi::shared::winerror::ERROR_INVALID_FUNCTION; -use winapi::um::fileapi::LockFileEx; -use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, OVERLAPPED}; -use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; +use windows::{ + Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE}, + Win32::Storage::FileSystem::{ + LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK, + LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS, + }, + Win32::System::IO::OVERLAPPED, +}; #[derive(Debug)] pub struct Lock { @@ -25,7 +28,7 @@ impl Lock { let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; let mut open_options = OpenOptions::new(); - open_options.read(true).share_mode(share_mode); + open_options.read(true).share_mode(share_mode.0); if create { open_options.create(true).write(true); @@ -43,33 +46,42 @@ impl Lock { } }; - let ret = unsafe { - let mut overlapped: OVERLAPPED = mem::zeroed(); + let mut flags = LOCK_FILE_FLAGS::default(); + if !wait { + flags |= LOCKFILE_FAIL_IMMEDIATELY; + } - let mut dwFlags = 0; - if !wait { - dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; - } + if exclusive { + flags |= LOCKFILE_EXCLUSIVE_LOCK; + } - if exclusive { - dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; - } + let mut overlapped = OVERLAPPED::default(); - debug!("attempting to acquire lock on lock file `{}`", p.display()); - LockFileEx(file.as_raw_handle(), dwFlags, 0, 0xFFFF_FFFF, 0xFFFF_FFFF, &mut overlapped) - }; - if ret == 0 { - let err = io::Error::last_os_error(); - debug!("failed acquiring file lock: {}", err); - Err(err) - } else { - debug!("successfully acquired lock"); - Ok(Lock { _file: file }) + debug!("attempting to acquire lock on lock file `{}`", p.display()); + + unsafe { + LockFileEx( + HANDLE(file.as_raw_handle() as isize), + flags, + 0, + u32::MAX, + u32::MAX, + &mut overlapped, + ) } + .ok() + .map_err(|e| { + let err = io::Error::from_raw_os_error(e.code().0); + debug!("failed acquiring file lock: {}", err); + err + })?; + + debug!("successfully acquired lock"); + Ok(Lock { _file: file }) } pub fn error_unsupported(err: &io::Error) -> bool { - err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32) + err.raw_os_error() == Some(ERROR_INVALID_FUNCTION.0 as i32) } } diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 820a70fc8e4..513df666d0d 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -56,7 +56,7 @@ fn test_three_sccs() { assert_eq!(sccs.scc(1), 0); assert_eq!(sccs.scc(2), 0); assert_eq!(sccs.scc(3), 2); - assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(0), &[] as &[usize]); assert_eq!(sccs.successors(1), &[0]); assert_eq!(sccs.successors(2), &[0]); } @@ -113,7 +113,7 @@ fn test_find_state_2() { assert_eq!(sccs.scc(2), 0); assert_eq!(sccs.scc(3), 0); assert_eq!(sccs.scc(4), 0); - assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(0), &[] as &[usize]); } #[test] @@ -138,7 +138,7 @@ fn test_find_state_3() { assert_eq!(sccs.scc(3), 0); assert_eq!(sccs.scc(4), 0); assert_eq!(sccs.scc(5), 1); - assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(0), &[] as &[usize]); assert_eq!(sccs.successors(1), &[0]); } diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs index c8f97926717..7c866da6009 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs @@ -27,11 +27,11 @@ fn successors() { let graph = create_graph(); assert_eq!(graph.successors(0), &[1]); assert_eq!(graph.successors(1), &[2, 3]); - assert_eq!(graph.successors(2), &[]); + assert_eq!(graph.successors(2), &[] as &[usize]); assert_eq!(graph.successors(3), &[4]); - assert_eq!(graph.successors(4), &[]); + assert_eq!(graph.successors(4), &[] as &[usize]); assert_eq!(graph.successors(5), &[1]); - assert_eq!(graph.successors(6), &[]); + assert_eq!(graph.successors(6), &[] as &[usize]); } #[test] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index c595bf830a3..0339fb925d4 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -79,7 +79,6 @@ pub mod sync; pub mod tiny_list; pub mod transitive_relation; pub mod vec_linked_list; -pub mod vec_map; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 91abdaadabd..27a869eb7cd 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -97,7 +97,17 @@ pub trait ObligationProcessor { type Error: Debug; type OUT: OutcomeTrait<Obligation = Self::Obligation, Error = Error<Self::Obligation, Self::Error>>; - fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool; + /// Implementations can provide a fast-path to obligation-processing + /// by counting the prefix of the passed iterator for which + /// `needs_process_obligation` would return false. + fn skippable_obligations<'a>( + &'a self, + _it: impl Iterator<Item = &'a Self::Obligation>, + ) -> usize { + 0 + } + + fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool; fn process_obligation( &mut self, @@ -416,6 +426,10 @@ impl<O: ForestObligation> ObligationForest<O> { loop { let mut has_changed = false; + // This is the super fast path for cheap-to-check conditions. + let mut index = + processor.skippable_obligations(self.nodes.iter().map(|n| &n.obligation)); + // Note that the loop body can append new nodes, and those new nodes // will then be processed by subsequent iterations of the loop. // @@ -424,9 +438,8 @@ impl<O: ForestObligation> ObligationForest<O> { // `for index in 0..self.nodes.len() { ... }` because the range would // be computed with the initial length, and we would miss the appended // nodes. Therefore we use a `while` loop. - let mut index = 0; while let Some(node) = self.nodes.get_mut(index) { - // This test is extremely hot. + // This is the moderately fast path when the prefix skipping above didn't work out. if node.state.get() != NodeState::Pending || !processor.needs_process_obligation(&node.obligation) { diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 44331683694..58a0609e296 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -97,6 +97,7 @@ use std::time::{Duration, Instant}; pub use measureme::EventId; use measureme::{EventIdBuilder, Profiler, SerializableString, StringId}; use parking_lot::RwLock; +use serde_json::json; use smallvec::SmallVec; bitflags::bitflags! { @@ -145,6 +146,15 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[ /// Something that uniquely identifies a query invocation. pub struct QueryInvocationId(pub u32); +/// Which format to use for `-Z time-passes` +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum TimePassesFormat { + /// Emit human readable text + Text, + /// Emit structured JSON + Json, +} + /// A reference to the SelfProfiler. It can be cloned and sent across thread /// boundaries at will. #[derive(Clone)] @@ -158,14 +168,14 @@ pub struct SelfProfilerRef { // actually enabled. event_filter_mask: EventFilter, - // Print verbose generic activities to stderr? - print_verbose_generic_activities: bool, + // Print verbose generic activities to stderr. + print_verbose_generic_activities: Option<TimePassesFormat>, } impl SelfProfilerRef { pub fn new( profiler: Option<Arc<SelfProfiler>>, - print_verbose_generic_activities: bool, + print_verbose_generic_activities: Option<TimePassesFormat>, ) -> SelfProfilerRef { // If there is no SelfProfiler then the filter mask is set to NONE, // ensuring that nothing ever tries to actually access it. @@ -207,9 +217,10 @@ impl SelfProfilerRef { /// a measureme event, "verbose" generic activities also print a timing entry to /// stderr if the compiler is invoked with -Ztime-passes. pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> { - let message = self.print_verbose_generic_activities.then(|| event_label.to_owned()); + let message_and_format = + self.print_verbose_generic_activities.map(|format| (event_label.to_owned(), format)); - VerboseTimingGuard::start(message, self.generic_activity(event_label)) + VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label)) } /// Like `verbose_generic_activity`, but with an extra arg. @@ -221,11 +232,14 @@ impl SelfProfilerRef { where A: Borrow<str> + Into<String>, { - let message = self + let message_and_format = self .print_verbose_generic_activities - .then(|| format!("{}({})", event_label, event_arg.borrow())); + .map(|format| (format!("{}({})", event_label, event_arg.borrow()), format)); - VerboseTimingGuard::start(message, self.generic_activity_with_arg(event_label, event_arg)) + VerboseTimingGuard::start( + message_and_format, + self.generic_activity_with_arg(event_label, event_arg), + ) } /// Start profiling a generic activity. Profiling continues until the @@ -703,17 +717,32 @@ impl<'a> TimingGuard<'a> { } } +struct VerboseInfo { + start_time: Instant, + start_rss: Option<usize>, + message: String, + format: TimePassesFormat, +} + #[must_use] pub struct VerboseTimingGuard<'a> { - start_and_message: Option<(Instant, Option<usize>, String)>, + info: Option<VerboseInfo>, _guard: TimingGuard<'a>, } impl<'a> VerboseTimingGuard<'a> { - pub fn start(message: Option<String>, _guard: TimingGuard<'a>) -> Self { + pub fn start( + message_and_format: Option<(String, TimePassesFormat)>, + _guard: TimingGuard<'a>, + ) -> Self { VerboseTimingGuard { _guard, - start_and_message: message.map(|msg| (Instant::now(), get_resident_set_size(), msg)), + info: message_and_format.map(|(message, format)| VerboseInfo { + start_time: Instant::now(), + start_rss: get_resident_set_size(), + message, + format, + }), } } @@ -726,10 +755,10 @@ impl<'a> VerboseTimingGuard<'a> { impl Drop for VerboseTimingGuard<'_> { fn drop(&mut self) { - if let Some((start_time, start_rss, ref message)) = self.start_and_message { + if let Some(info) = &self.info { let end_rss = get_resident_set_size(); - let dur = start_time.elapsed(); - print_time_passes_entry(message, dur, start_rss, end_rss); + let dur = info.start_time.elapsed(); + print_time_passes_entry(&info.message, dur, info.start_rss, end_rss, info.format); } } } @@ -739,7 +768,22 @@ pub fn print_time_passes_entry( dur: Duration, start_rss: Option<usize>, end_rss: Option<usize>, + format: TimePassesFormat, ) { + match format { + TimePassesFormat::Json => { + let json = json!({ + "pass": what, + "time": dur.as_secs_f64(), + "rss_start": start_rss, + "rss_end": end_rss, + }); + eprintln!("time: {}", json.to_string()); + return; + } + TimePassesFormat::Text => (), + } + // Print the pass if its duration is greater than 5 ms, or it changed the // measured RSS. let is_notable = || { @@ -796,21 +840,26 @@ fn get_thread_id() -> u32 { cfg_if! { if #[cfg(windows)] { pub fn get_resident_set_size() -> Option<usize> { - use std::mem::{self, MaybeUninit}; - use winapi::shared::minwindef::DWORD; - use winapi::um::processthreadsapi::GetCurrentProcess; - use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}; - - let mut pmc = MaybeUninit::<PROCESS_MEMORY_COUNTERS>::uninit(); - match unsafe { - GetProcessMemoryInfo(GetCurrentProcess(), pmc.as_mut_ptr(), mem::size_of_val(&pmc) as DWORD) - } { - 0 => None, - _ => { - let pmc = unsafe { pmc.assume_init() }; - Some(pmc.WorkingSetSize as usize) - } + use std::mem; + + use windows::{ + Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, + Win32::System::Threading::GetCurrentProcess, + }; + + let mut pmc = PROCESS_MEMORY_COUNTERS::default(); + let pmc_size = mem::size_of_val(&pmc); + unsafe { + K32GetProcessMemoryInfo( + GetCurrentProcess(), + &mut pmc, + pmc_size as u32, + ) } + .ok() + .ok()?; + + Some(pmc.WorkingSetSize) } } else if #[cfg(target_os = "macos")] { pub fn get_resident_set_size() -> Option<usize> { diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs deleted file mode 100644 index d1a99bcaeb7..00000000000 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ /dev/null @@ -1,192 +0,0 @@ -use std::borrow::Borrow; -use std::fmt::Debug; -use std::slice::Iter; -use std::vec::IntoIter; - -use crate::stable_hasher::{HashStable, StableHasher}; - -/// A map type implemented as a vector of pairs `K` (key) and `V` (value). -/// It currently provides a subset of all the map operations, the rest could be added as needed. -#[derive(Clone, Encodable, Decodable, Debug)] -pub struct VecMap<K, V>(Vec<(K, V)>); - -impl<K, V> VecMap<K, V> -where - K: Debug + PartialEq, - V: Debug, -{ - pub fn new() -> Self { - VecMap(Default::default()) - } - - /// Sets the value of the entry, and returns the entry's old value. - pub fn insert(&mut self, k: K, v: V) -> Option<V> { - if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) { - Some(std::mem::replace(&mut elem.1, v)) - } else { - self.0.push((k, v)); - None - } - } - - /// Removes the entry from the map and returns the removed value - pub fn remove(&mut self, k: &K) -> Option<V> { - self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1) - } - - /// Gets a reference to the value in the entry. - pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> - where - K: Borrow<Q>, - Q: Eq, - { - self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1) - } - - /// Gets a mutable reference to the value in the entry. - pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow<Q>, - Q: Eq, - { - self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1) - } - - /// Returns the any value corresponding to the supplied predicate filter. - /// - /// The supplied predicate will be applied to each (key, value) pair and it will return a - /// reference to the values where the predicate returns `true`. - pub fn any_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> { - self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1) - } - - /// Returns the value corresponding to the supplied predicate filter. It crashes if there's - /// more than one matching element. - /// - /// The supplied predicate will be applied to each (key, value) pair and it will return a - /// reference to the value where the predicate returns `true`. - pub fn get_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> { - let mut filter = self.0.iter().filter(|kv| predicate(kv)); - let (_, value) = filter.next()?; - // This should return just one element, otherwise it's a bug - assert!( - filter.next().is_none(), - "Collection {self:#?} should have just one matching element" - ); - Some(value) - } - - /// Returns `true` if the map contains a value for the specified key. - /// - /// The key may be any borrowed form of the map's key type, - /// [`Eq`] on the borrowed form *must* match those for - /// the key type. - pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool - where - K: Borrow<Q>, - Q: Eq, - { - self.get(k).is_some() - } - - /// Returns `true` if the map contains no elements. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn iter(&self) -> Iter<'_, (K, V)> { - self.into_iter() - } - - pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> { - self.into_iter() - } - - pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) { - self.0.retain(f) - } -} - -impl<K, V> Default for VecMap<K, V> { - #[inline] - fn default() -> Self { - Self(Default::default()) - } -} - -impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> { - fn from(vec: Vec<(K, V)>) -> Self { - Self(vec) - } -} - -impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> { - fn into(self) -> Vec<(K, V)> { - self.0 - } -} - -impl<K, V> FromIterator<(K, V)> for VecMap<K, V> { - fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self { - Self(iter.into_iter().collect()) - } -} - -impl<'a, K, V> IntoIterator for &'a VecMap<K, V> { - type Item = &'a (K, V); - type IntoIter = Iter<'a, (K, V)>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut VecMap<K, V> { - type Item = (&'a K, &'a mut V); - type IntoIter = impl Iterator<Item = Self::Item>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut().map(|(k, v)| (&*k, v)) - } -} - -impl<K, V> IntoIterator for VecMap<K, V> { - type Item = (K, V); - type IntoIter = IntoIter<(K, V)>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<K: PartialEq + Debug, V: Debug> Extend<(K, V)> for VecMap<K, V> { - fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) { - for (k, v) in iter { - self.insert(k, v); - } - } - - fn extend_one(&mut self, (k, v): (K, V)) { - self.insert(k, v); - } - - fn extend_reserve(&mut self, additional: usize) { - self.0.extend_reserve(additional); - } -} - -impl<K, V, CTX> HashStable<CTX> for VecMap<K, V> -where - K: HashStable<CTX> + Eq, - V: HashStable<CTX>, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.0.hash_stable(hcx, hasher) - } -} - -#[cfg(test)] -mod tests; diff --git a/compiler/rustc_data_structures/src/vec_map/tests.rs b/compiler/rustc_data_structures/src/vec_map/tests.rs deleted file mode 100644 index 458b60077dc..00000000000 --- a/compiler/rustc_data_structures/src/vec_map/tests.rs +++ /dev/null @@ -1,48 +0,0 @@ -use super::*; - -impl<K, V> VecMap<K, V> { - fn into_vec(self) -> Vec<(K, V)> { - self.0.into() - } -} - -#[test] -fn test_from_iterator() { - assert_eq!( - std::iter::empty().collect::<VecMap<i32, bool>>().into_vec(), - Vec::<(i32, bool)>::new() - ); - assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]); - assert_eq!( - [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(), - vec![(1, true), (2, false)] - ); -} - -#[test] -fn test_into_iterator_owned() { - assert_eq!(VecMap::new().into_iter().collect::<Vec<(i32, bool)>>(), Vec::<(i32, bool)>::new()); - assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::<Vec<_>>(), vec![(1, true)]); - assert_eq!( - VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::<Vec<_>>(), - vec![(1, true), (2, false)] - ); -} - -#[test] -fn test_insert() { - let mut v = VecMap::new(); - assert_eq!(v.insert(1, true), None); - assert_eq!(v.insert(2, false), None); - assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]); - assert_eq!(v.insert(1, false), Some(true)); - assert_eq!(v.into_vec(), vec![(1, false), (2, false)]); -} - -#[test] -fn test_get() { - let v = [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>(); - assert_eq!(v.get(&1), Some(&true)); - assert_eq!(v.get(&2), Some(&false)); - assert_eq!(v.get(&3), None); -} diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 7b59a52cffe..73a1f79a020 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -54,8 +54,11 @@ rustc_hir_analysis = { path = "../rustc_hir_analysis" } [target.'cfg(unix)'.dependencies] libc = "0.2" -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] } +[target.'cfg(windows)'.dependencies.windows] +version = "0.46.0" +features = [ + "Win32_System_Diagnostics_Debug", +] [features] llvm = ['rustc_interface/llvm'] diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 555917c8b5e..1e835f6065a 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -20,7 +20,9 @@ pub extern crate rustc_plugin_impl as plugin; use rustc_ast as ast; use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; -use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; +use rustc_data_structures::profiling::{ + get_resident_set_size, print_time_passes_entry, TimePassesFormat, +}; use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ @@ -161,7 +163,7 @@ pub trait Callbacks { #[derive(Default)] pub struct TimePassesCallbacks { - time_passes: bool, + time_passes: Option<TimePassesFormat>, } impl Callbacks for TimePassesCallbacks { @@ -171,7 +173,8 @@ impl Callbacks for TimePassesCallbacks { // If a --print=... option has been given, we don't print the "total" // time because it will mess up the --print output. See #64339. // - self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes; + self.time_passes = (config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes) + .then(|| config.opts.unstable_opts.time_passes_format); config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath; } } @@ -353,7 +356,7 @@ fn run_compiler( { let plugins = queries.register_plugins()?; - let (_, lint_store) = &*plugins.borrow(); + let (.., lint_store) = &*plugins.borrow(); // Lint plugins are registered; now we can process command line flags. if sess.opts.describe_lints { @@ -1246,11 +1249,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { interface::try_print_query_stack(&handler, num_frames); #[cfg(windows)] - unsafe { - if env::var("RUSTC_BREAK_ON_ICE").is_ok() { - // Trigger a debugger if we crashed during bootstrap - winapi::um::debugapi::DebugBreak(); - } + if env::var("RUSTC_BREAK_ON_ICE").is_ok() { + // Trigger a debugger if we crashed during bootstrap + unsafe { windows::Win32::System::Diagnostics::Debug::DebugBreak() }; } } @@ -1356,9 +1357,9 @@ pub fn main() -> ! { RunCompiler::new(&args, &mut callbacks).run() }); - if callbacks.time_passes { + if let Some(format) = callbacks.time_passes { let end_rss = get_resident_set_size(); - print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss); + print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss, format); } process::exit(exit_code) diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index df857be85ad..d104ff0891d 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -513,6 +513,7 @@ E0790: include_str!("./error_codes/E0790.md"), E0791: include_str!("./error_codes/E0791.md"), E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), +E0794: include_str!("./error_codes/E0794.md"), } // Undocumented removed error codes. Note that many removed error codes are documented. diff --git a/compiler/rustc_error_codes/src/error_codes/E0080.md b/compiler/rustc_error_codes/src/error_codes/E0080.md index 7b1bbde6140..71d6c6fe2ef 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0080.md +++ b/compiler/rustc_error_codes/src/error_codes/E0080.md @@ -15,9 +15,8 @@ or causing an integer overflow are two ways to induce this error. Ensure that the expressions given can be evaluated as the desired integer type. -See the [Custom Discriminants][custom-discriminants] section of the Reference -for more information about setting custom integer types on fieldless enums -using the [`repr` attribute][repr-attribute]. +See the [Discriminants] section of the Reference for more information about +setting custom integer types on enums using the [`repr` attribute][repr-attribute]. -[custom-discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations -[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#reprc-enums +[discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#discriminants +[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations diff --git a/compiler/rustc_error_codes/src/error_codes/E0206.md b/compiler/rustc_error_codes/src/error_codes/E0206.md index 4405a2149ce..9e85234bdbb 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0206.md +++ b/compiler/rustc_error_codes/src/error_codes/E0206.md @@ -1,5 +1,5 @@ -The `Copy` trait was implemented on a type which is neither a struct nor an -enum. +The `Copy` trait was implemented on a type which is neither a struct, an +enum, nor a union. Erroneous code example: @@ -10,6 +10,6 @@ struct Bar; impl Copy for &'static mut Bar { } // error! ``` -You can only implement `Copy` for a struct or an enum. +You can only implement `Copy` for a struct, an enum, or a union. The previous example will fail because `&'static mut Bar` -is not a struct or enum. +is not a struct, an enum, or a union. diff --git a/compiler/rustc_error_codes/src/error_codes/E0416.md b/compiler/rustc_error_codes/src/error_codes/E0416.md index 7bc316dafc5..8c0edcee521 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0416.md +++ b/compiler/rustc_error_codes/src/error_codes/E0416.md @@ -23,6 +23,6 @@ Or maybe did you mean to unify? Consider using a guard: # let (A, B, C) = (1, 2, 3); match (A, B, C) { (x, x2, see) if x == x2 => { /* A and B are equal, do one thing */ } - (y, z, see) => { /* A and B unequal; do another thing */ } + (y, z, see) => { /* A and B not equal; do another thing */ } } ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md new file mode 100644 index 00000000000..4377a292473 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0794.md @@ -0,0 +1,64 @@ +A lifetime parameter of a function definition is called *late-bound* if it both: + +1. appears in an argument type +2. does not appear in a generic type constraint + +You cannot specify lifetime arguments for late-bound lifetime parameters. + +Erroneous code example: + +```compile_fail,E0794 +fn foo<'a>(x: &'a str) -> &'a str { x } +let _ = foo::<'static>; +``` + +The type of a concrete instance of a generic function is universally quantified +over late-bound lifetime parameters. This is because we want the function to +work for any lifetime substituted for the late-bound lifetime parameter, no +matter where the function is called. Consequently, it doesn't make sense to +specify arguments for late-bound lifetime parameters, since they are not +resolved until the function's call site(s). + +To fix the issue, remove the specified lifetime: + +``` +fn foo<'a>(x: &'a str) -> &'a str { x } +let _ = foo; +``` + +### Additional information + +Lifetime parameters that are not late-bound are called *early-bound*. +Confusion may arise from the fact that late-bound and early-bound +lifetime parameters are declared the same way in function definitions. +When referring to a function pointer type, universal quantification over +late-bound lifetime parameters can be made explicit: + +``` +trait BarTrait<'a> {} + +struct Bar<'a> { + s: &'a str +} + +impl<'a> BarTrait<'a> for Bar<'a> {} + +fn bar<'a, 'b, T>(x: &'a str, _t: T) -> &'a str +where T: BarTrait<'b> +{ + x +} + +let bar_fn: for<'a> fn(&'a str, Bar<'static>) -> &'a str = bar; // OK +let bar_fn2 = bar::<'static, Bar>; // Not allowed +let bar_fn3 = bar::<Bar>; // OK +``` + +In the definition of `bar`, the lifetime parameter `'a` is late-bound, while +`'b` is early-bound. This is reflected in the type annotation for `bar_fn`, +where `'a` is universally quantified and `'b` is substituted by a specific +lifetime. It is not allowed to explicitly specify early-bound lifetime +arguments when late-bound lifetime parameters are present (as for `bar_fn2`, +see [issue #42868](https://github.com/rust-lang/rust/issues/42868)), although the +types that are constrained by early-bound parameters can be specified (as for +`bar_fn3`). diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index cadd53fbd83..e1ead08ea66 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -25,8 +25,14 @@ termize = "0.1.1" serde = { version = "1.0.125", features = [ "derive" ] } serde_json = "1.0.59" -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] } +[target.'cfg(windows)'.dependencies.windows] +version = "0.46.0" +features = [ + "Win32_Foundation", + "Win32_Security", + "Win32_System_Threading", + "Win32_System_WindowsProgramming", +] [features] rustc_use_parallel_compiler = ['rustc_error_messages/rustc_use_parallel_compiler'] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bab4f31e777..9866a9bffe0 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -331,7 +331,7 @@ impl CodeSuggestion { }); buf.push_str(&part.snippet); let cur_hi = sm.lookup_char_pos(part.span.hi()); - if cur_hi.line == cur_lo.line { + if cur_hi.line == cur_lo.line && !part.snippet.is_empty() { // Account for the difference between the width of the current code and the // snippet being suggested, so that the *later* suggestions are correctly // aligned on the screen. diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs index a73472021d4..7db262abfde 100644 --- a/compiler/rustc_errors/src/lock.rs +++ b/compiler/rustc_errors/src/lock.rs @@ -16,10 +16,12 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> { use std::ffi::CString; use std::io; - use winapi::shared::ntdef::HANDLE; - use winapi::um::handleapi::CloseHandle; - use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject}; - use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0}; + use windows::{ + core::PCSTR, + Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0}, + Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject}, + Win32::System::WindowsProgramming::INFINITE, + }; struct Handle(HANDLE); @@ -42,49 +44,38 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> { } let cname = CString::new(name).unwrap(); - unsafe { - // Create a named mutex, with no security attributes and also not - // acquired when we create it. - // - // This will silently create one if it doesn't already exist, or it'll - // open up a handle to one if it already exists. - let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr()); - if mutex.is_null() { - panic!( - "failed to create global mutex named `{}`: {}", - name, - io::Error::last_os_error() - ); - } - let mutex = Handle(mutex); + // Create a named mutex, with no security attributes and also not + // acquired when we create it. + // + // This will silently create one if it doesn't already exist, or it'll + // open up a handle to one if it already exists. + let mutex = unsafe { CreateMutexA(None, false, PCSTR::from_raw(cname.as_ptr().cast())) } + .unwrap_or_else(|_| panic!("failed to create global mutex named `{}`", name)); + let mutex = Handle(mutex); - // Acquire the lock through `WaitForSingleObject`. - // - // A return value of `WAIT_OBJECT_0` means we successfully acquired it. - // - // A return value of `WAIT_ABANDONED` means that the previous holder of - // the thread exited without calling `ReleaseMutex`. This can happen, - // for example, when the compiler crashes or is interrupted via ctrl-c - // or the like. In this case, however, we are still transferred - // ownership of the lock so we continue. - // - // If an error happens.. well... that's surprising! - match WaitForSingleObject(mutex.0, INFINITE) { - WAIT_OBJECT_0 | WAIT_ABANDONED => {} - code => { - panic!( - "WaitForSingleObject failed on global mutex named \ - `{}`: {} (ret={:x})", - name, - io::Error::last_os_error(), - code - ); - } - } - - // Return a guard which will call `ReleaseMutex` when dropped. - Box::new(Guard(mutex)) + // Acquire the lock through `WaitForSingleObject`. + // + // A return value of `WAIT_OBJECT_0` means we successfully acquired it. + // + // A return value of `WAIT_ABANDONED` means that the previous holder of + // the thread exited without calling `ReleaseMutex`. This can happen, + // for example, when the compiler crashes or is interrupted via ctrl-c + // or the like. In this case, however, we are still transferred + // ownership of the lock so we continue. + // + // If an error happens.. well... that's surprising! + match unsafe { WaitForSingleObject(mutex.0, INFINITE) } { + WAIT_OBJECT_0 | WAIT_ABANDONED => (), + err => panic!( + "WaitForSingleObject failed on global mutex named `{}`: {} (ret={:x})", + name, + io::Error::last_os_error(), + err.0 + ), } + + // Return a guard which will call `ReleaseMutex` when dropped. + Box::new(Guard(mutex)) } #[cfg(not(windows))] diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 713e4fbbdce..d32af10914e 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -776,16 +776,14 @@ impl SyntaxExtension { let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>(); - let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe); - let local_inner_macros = sess - .find_by_name(attrs, sym::macro_export) + let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe); + let local_inner_macros = attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) .map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros)); - let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo); + let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo); tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); - let (builtin_name, helper_attrs) = sess - .find_by_name(attrs, sym::rustc_builtin_macro) + let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro) .map(|attr| { // Override `helper_attrs` passed above if it's a built-in macro, // marking `proc_macro_derive` macros as built-in is not a realistic use case. @@ -1004,6 +1002,7 @@ pub struct ExpansionData { pub struct ExtCtxt<'a> { pub sess: &'a Session, pub ecfg: expand::ExpansionConfig<'a>, + pub num_standard_library_imports: usize, pub reduced_recursion_limit: Option<Limit>, pub root_path: PathBuf, pub resolver: &'a mut dyn ResolverExpand, @@ -1032,6 +1031,7 @@ impl<'a> ExtCtxt<'a> { ExtCtxt { sess, ecfg, + num_standard_library_imports: 0, reduced_recursion_limit: None, resolver, lint_store, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index d6cb173ba9b..a78dc0678d5 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -24,7 +24,6 @@ use rustc_session::Session; use rustc_span::edition::{Edition, ALL_EDITIONS}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use thin_vec::ThinVec; /// A folder that strips out items that do not belong in the current configuration. pub struct StripUnconfigured<'a> { @@ -37,7 +36,7 @@ pub struct StripUnconfigured<'a> { pub lint_node_id: NodeId, } -fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { +pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) { sess.emit_err(FeatureRemoved { span, @@ -191,39 +190,16 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { features } -/// `cfg_attr`-process the crate's attributes and compute the crate's features. -pub fn features( - sess: &Session, - mut krate: ast::Crate, - lint_node_id: NodeId, -) -> (ast::Crate, Features) { - let mut strip_unconfigured = - StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id }; - - let unconfigured_attrs = krate.attrs.clone(); - let diag = &sess.parse_sess.span_diagnostic; - let err_count = diag.err_count(); - let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) { - None => { - // The entire crate is unconfigured. - krate.attrs = ast::AttrVec::new(); - krate.items = ThinVec::new(); - Features::default() - } - Some(attrs) => { - krate.attrs = attrs; - let features = get_features(sess, &krate.attrs); - if err_count == diag.err_count() { - // Avoid reconfiguring malformed `cfg_attr`s. - strip_unconfigured.features = Some(&features); - // Run configuration again, this time with features available - // so that we can perform feature-gating. - strip_unconfigured.configure_krate_attrs(unconfigured_attrs); - } - features - } +pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec { + let strip_unconfigured = StripUnconfigured { + sess, + features: None, + config_tokens: false, + lint_node_id: ast::CRATE_NODE_ID, }; - (krate, features) + let attrs: ast::AttrVec = + attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect(); + if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() } } #[macro_export] @@ -254,11 +230,6 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option<ast::AttrVec> { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); - self.in_cfg(&attrs).then_some(attrs) - } - /// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`. /// This is only used during the invocation of `derive` proc-macros, /// which require that we cfg-expand their entire input. @@ -281,7 +252,7 @@ impl<'a> StripUnconfigured<'a> { .iter() .flat_map(|tree| match tree.clone() { AttrTokenTree::Attributes(mut data) => { - data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); if self.in_cfg(&data.attrs) { data.tokens = LazyAttrTokenStream::new( @@ -319,12 +290,16 @@ impl<'a> StripUnconfigured<'a> { /// the syntax of any `cfg_attr` is incorrect. fn process_cfg_attrs<T: HasAttrs>(&self, node: &mut T) { node.visit_attrs(|attrs| { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); }); } - fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> { - if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] } + fn process_cfg_attr(&self, attr: &Attribute) -> Vec<Attribute> { + if attr.has_name(sym::cfg_attr) { + self.expand_cfg_attr(attr, true) + } else { + vec![attr.clone()] + } } /// Parse and expand a single `cfg_attr` attribute into a list of attributes @@ -334,9 +309,9 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> { + pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> { let Some((cfg_predicate, expanded_attrs)) = - rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else { + rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess) else { return vec![]; }; @@ -365,10 +340,10 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs .into_iter() - .flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item))) + .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item))) .collect() } else { - expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect() + expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect() } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 4092a192e0c..ec40911545f 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1038,6 +1038,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { ) -> Result<Self::OutputTy, Self> { Ok(noop_flat_map(node, collector)) } + fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) { + collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() }); + } } impl InvocationCollectorNode for P<ast::Item> { @@ -1378,6 +1381,11 @@ impl InvocationCollectorNode for ast::Crate { fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) { noop_visit_crate(self, visitor) } + fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) { + self.attrs.clear(); + // Standard prelude imports are left in the crate for backward compatibility. + self.items.truncate(collector.cx.num_standard_library_imports); + } } impl InvocationCollectorNode for P<ast::Ty> { @@ -1688,7 +1696,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { res } - fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) { + fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) { node.visit_attrs(|attrs| { // Repeated `insert` calls is inefficient, but the number of // insertions is almost always 0 or 1 in practice. @@ -1712,7 +1720,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Default::default() } sym::cfg_attr => { - self.expand_cfg_attr(&mut node, attr, pos); + self.expand_cfg_attr(&mut node, &attr, pos); continue; } _ => { @@ -1756,11 +1764,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { continue; } - self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() }); + node.expand_cfg_false(self, span); continue; } sym::cfg_attr => { - self.expand_cfg_attr(node, attr, pos); + self.expand_cfg_attr(node, &attr, pos); continue; } _ => visit_clobber(node, |node| { diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index b1d9cea2773..6bc393c6534 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -245,12 +245,24 @@ pub(super) fn emit_frag_parse_err( e.note( "the macro call doesn't expand to an expression, but it can expand to a statement", ); - e.span_suggestion_verbose( - site_span.shrink_to_hi(), - "add `;` to interpret the expansion as a statement", - ";", - Applicability::MaybeIncorrect, - ); + + if parser.token == token::Semi { + if let Ok(snippet) = parser.sess.source_map().span_to_snippet(site_span) { + e.span_suggestion_verbose( + site_span, + "surround the macro invocation with `{}` to interpret the expansion as a statement", + format!("{{ {}; }}", snippet), + Applicability::MaybeIncorrect, + ); + } + } else { + e.span_suggestion_verbose( + site_span.shrink_to_hi(), + "add `;` to interpret the expansion as a statement", + ";", + Applicability::MaybeIncorrect, + ); + } } }, _ => annotate_err_with_kind(&mut e, kind, site_span), diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 47a8b4bc488..a07cb65170d 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -367,7 +367,7 @@ impl LockstepIterSize { /// /// Example: `$($($x $y)+*);+` -- we need to make sure that `x` and `y` repeat the same amount as /// each other at the given depth when the macro was invoked. If they don't it might mean they were -/// declared at unequal depths or there was a compile bug. For example, if we have 3 repetitions of +/// declared at depths which weren't equal or there was a compiler bug. For example, if we have 3 repetitions of /// the outer sequence and 4 repetitions of the inner sequence for `x`, we should have the same for /// `y`; otherwise, we can't transcribe them both at the given depth. fn lockstep_iter_size( diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ac93dd555b7..3d644de1665 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -91,7 +91,7 @@ declare_features! ( /// Allows coercing non capturing closures to function pointers. (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), /// Allows using the CMPXCHG16B target feature. - (accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None), + (accepted, cmpxchg16b_target_feature, "1.69.0", Some(44839), None), /// Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872), None), /// Allows `impl Trait` in function return types. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index c893b34b4ac..b7d280b8751 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -160,8 +160,10 @@ declare_features! ( (active, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), + /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406 + (active, link_cfg, "1.14.0", None, None), /// Allows the `multiple_supertrait_upcastable` lint. - (active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None), + (active, multiple_supertrait_upcastable, "1.69.0", None, None), /// Allows using `#[omit_gdb_pretty_printer_section]`. (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), /// Allows using `#[prelude_import]` on glob `use` items. @@ -214,7 +216,7 @@ declare_features! ( /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. (active, needs_panic_runtime, "1.10.0", Some(32837), None), /// Allows using `+bundled,+whole-archive` native libs. - (active, packed_bundled_libs, "CURRENT_RUSTC_VERSION", Some(108081), None), + (active, packed_bundled_libs, "1.69.0", Some(108081), None), /// Allows using the `#![panic_runtime]` attribute. (active, panic_runtime, "1.10.0", Some(32837), None), /// Allows using `#[rustc_allow_const_fn_unstable]`. @@ -432,8 +434,6 @@ declare_features! ( (active, large_assignments, "1.52.0", Some(83518), None), /// Allows `if/while p && let q = r && ...` chains. (active, let_chains, "1.37.0", Some(53667), None), - /// Allows `#[link(..., cfg(..))]`. - (active, link_cfg, "1.14.0", Some(37406), None), /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. (active, lint_reasons, "1.31.0", Some(54503), None), /// Give access to additional metadata about declarative macro meta-variables. @@ -468,7 +468,7 @@ declare_features! ( /// Allows using the `non_exhaustive_omitted_patterns` lint. (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None), /// Allows `for<T>` binders in where-clauses - (incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(108185), None), + (incomplete, non_lifetime_binders, "1.69.0", Some(108185), None), /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index a7dfce3b9b8..81d63338145 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,10 +1,11 @@ +#![feature(absolute_path)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] use std::ffi::CString; use std::fs; use std::io; -use std::path::{Path, PathBuf}; +use std::path::{absolute, Path, PathBuf}; // Unfortunately, on windows, it looks like msvcrt.dll is silently translating // verbatim paths under the hood to non-verbatim paths! This manifests itself as @@ -91,3 +92,8 @@ pub fn path_to_c_string(p: &Path) -> CString { pub fn path_to_c_string(p: &Path) -> CString { CString::new(p.to_str().unwrap()).unwrap() } + +#[inline] +pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { + fs::canonicalize(&path).or_else(|_| absolute(&path)) +} diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f00a5f24e45..f4b46b9a131 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1673,7 +1673,6 @@ pub struct Expr<'hir> { impl Expr<'_> { pub fn precedence(&self) -> ExprPrecedence { match self.kind { - ExprKind::Box(_) => ExprPrecedence::Box, ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock, ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Call(..) => ExprPrecedence::Call, @@ -1763,7 +1762,6 @@ impl Expr<'_> { | ExprKind::Lit(_) | ExprKind::ConstBlock(..) | ExprKind::Unary(..) - | ExprKind::Box(..) | ExprKind::AddrOf(..) | ExprKind::Binary(..) | ExprKind::Yield(..) @@ -1851,7 +1849,6 @@ impl Expr<'_> { | ExprKind::InlineAsm(..) | ExprKind::AssignOp(..) | ExprKind::ConstBlock(..) - | ExprKind::Box(..) | ExprKind::Binary(..) | ExprKind::Yield(..) | ExprKind::DropTemps(..) @@ -1862,8 +1859,7 @@ impl Expr<'_> { /// To a first-order approximation, is this a pattern? pub fn is_approximately_pattern(&self) -> bool { match &self.kind { - ExprKind::Box(_) - | ExprKind::Array(_) + ExprKind::Array(_) | ExprKind::Call(..) | ExprKind::Tup(_) | ExprKind::Lit(_) @@ -1910,8 +1906,6 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { #[derive(Debug, HashStable_Generic)] pub enum ExprKind<'hir> { - /// A `box x` expression. - Box(&'hir Expr<'hir>), /// Allow anonymous constants from an inline `const` block ConstBlock(AnonConst), /// An array (e.g., `[a, b, c, d]`). diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 404abe2b068..37ac3723161 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -22,6 +22,12 @@ impl From<OwnerId> for HirId { } } +impl From<OwnerId> for DefId { + fn from(value: OwnerId) -> Self { + value.to_def_id() + } +} + impl OwnerId { #[inline] pub fn to_def_id(self) -> DefId { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index cc0f64017e4..234256ab553 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -682,7 +682,6 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) { visitor.visit_id(expression.hir_id); match expression.kind { - ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression), ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 72ff317d45d..0863d65d8f9 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -301,6 +301,7 @@ language_item_table! { Context, sym::Context, context, Target::Struct, GenericRequirement::None; FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + Option, sym::Option, option_type, Target::Enum, GenericRequirement::None; OptionSome, sym::Some, option_some_variant, Target::Variant, GenericRequirement::None; OptionNone, sym::None, option_none_variant, Target::Variant, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 2f4963f6bc3..3b5c67de239 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -612,7 +612,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( if position == GenericArgPosition::Value && args.num_lifetime_params() != param_counts.lifetimes { - let mut err = tcx.sess.struct_span_err(span, msg); + let mut err = struct_span_err!(tcx.sess, span, E0794, "{}", msg); err.span_note(span_late, note); err.emit(); } else { diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index f830269b45d..6d9dfe9697c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -31,6 +31,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::middle::stability::AllowUnstable; +use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::DynKind; use rustc_middle::ty::GenericParamDefKind; @@ -75,7 +76,7 @@ pub trait AstConv<'tcx> { fn get_type_parameter_bounds( &self, span: Span, - def_id: DefId, + def_id: LocalDefId, assoc_name: Ident, ) -> ty::GenericPredicates<'tcx>; @@ -1335,7 +1336,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(), }, ty::PredicateKind::WellFormed(_) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(_, _, _) | ty::PredicateKind::Subtype(_) @@ -1773,9 +1774,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty_param_def_id, assoc_name, span, ); - let predicates = &self - .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name) - .predicates; + let predicates = + &self.get_type_parameter_bounds(span, ty_param_def_id, assoc_name).predicates; debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); @@ -2226,47 +2226,66 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_env = tcx.param_env(block.owner.to_def_id()); let cause = ObligationCause::misc(span, block.owner.def_id); + let mut fulfillment_errors = Vec::new(); - let mut applicable_candidates: Vec<_> = candidates - .iter() - .filter_map(|&(impl_, (assoc_item, def_scope))| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new_in_snapshot(&infcx); + let mut applicable_candidates: Vec<_> = infcx.probe(|_| { + let universe = infcx.create_next_universe(); + + // Regions are not considered during selection. + let self_ty = tcx.replace_escaping_bound_vars_uncached( + self_ty, + FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_erased, + types: &mut |bv| { + tcx.mk_placeholder(ty::PlaceholderType { universe, name: bv.kind }) + }, + consts: &mut |bv, ty| { + tcx.mk_const(ty::PlaceholderConst { universe, name: bv }, ty) + }, + }, + ); - let impl_ty = tcx.type_of(impl_); - let impl_substs = infcx.fresh_item_substs(impl_); - let impl_ty = impl_ty.subst(tcx, impl_substs); - let impl_ty = ocx.normalize(&cause, param_env, impl_ty); + candidates + .iter() + .filter_map(|&(impl_, (assoc_item, def_scope))| { + infcx.probe(|_| { + let ocx = ObligationCtxt::new_in_snapshot(&infcx); - // Check that the Self-types can be related. - // FIXME(fmease): Should we use `eq` here? - ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?; + let impl_ty = tcx.type_of(impl_); + let impl_substs = infcx.fresh_item_substs(impl_); + let impl_ty = impl_ty.subst(tcx, impl_substs); + let impl_ty = ocx.normalize(&cause, param_env, impl_ty); - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_); - let impl_bounds = impl_bounds.instantiate(tcx, impl_substs); + // Check that the Self-types can be related. + // FIXME(fmease): Should we use `eq` here? + ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?; - let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds); + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = tcx.predicates_of(impl_); + let impl_bounds = impl_bounds.instantiate(tcx, impl_substs); - let impl_obligations = traits::predicates_for_generics( - |_, _| cause.clone(), - param_env, - impl_bounds, - ); + let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds); - ocx.register_obligations(impl_obligations); + let impl_obligations = traits::predicates_for_generics( + |_, _| cause.clone(), + param_env, + impl_bounds, + ); - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return None; - } + ocx.register_obligations(impl_obligations); - // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot. - Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs))) + let mut errors = ocx.select_where_possible(); + if !errors.is_empty() { + fulfillment_errors.append(&mut errors); + return None; + } + + // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot. + Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs))) + }) }) - }) - .collect(); + .collect() + }); if applicable_candidates.len() > 1 { return Err(self.complain_about_ambiguous_inherent_assoc_type( @@ -2396,13 +2415,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx, infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id), ); + // I guess we don't need to make a universe unless we need it, + // but also we're on the error path, so it doesn't matter here. + let universe = infcx.create_next_universe(); infcx .can_eq( ty::ParamEnv::empty(), impl_.self_ty(), - // Must fold past escaping bound vars too, - // since we have those at this point in astconv. - tcx.fold_regions(qself_ty, |_, _| tcx.lifetimes.re_erased), + tcx.replace_escaping_bound_vars_uncached(qself_ty, ty::fold::FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_erased, + types: &mut |bv| tcx.mk_placeholder(ty::PlaceholderType { + universe, + name: bv.kind, + }), + consts: &mut |bv, ty| tcx.mk_const(ty::PlaceholderConst { + universe, + name: bv + }, ty), + }) ) }) && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative @@ -3057,7 +3087,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // generate the def_id of an associated type for the trait and return as // type a projection. let def_id = if in_trait && tcx.lower_impl_trait_in_trait_to_assoc_ty() { - tcx.associated_item_for_impl_trait_in_trait(local_def_id).to_def_id() + tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id() } else { local_def_id.to_def_id() }; @@ -3141,8 +3171,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("impl_trait_ty_to_ty: generics={:?}", generics); let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { - if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { - // Our own parameters are the resolved lifetimes. + // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` + // since return-position impl trait in trait squashes all of the generics from its source fn + // into its own generics, so the opaque's "own" params isn't always just lifetimes. + if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len()) + { + // Resolve our own lifetime parameters. let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() }; let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() }; self.ast_region_to_region(lifetime, None).into() @@ -3317,10 +3351,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx, trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)), ); + let fn_sig = tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), fn_sig); - let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() }; - - Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty)) + Some(if let Some(arg_idx) = arg_idx { + *fn_sig.inputs().get(arg_idx)? + } else { + fn_sig.output() + }) } #[instrument(level = "trace", skip(self, generate_err))] diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 14dc9d89180..d8dda7a93be 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -211,7 +211,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { return; } - let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, item.owner_id); let span = tcx.def_span(item.owner_id.def_id); if !tcx.features().impl_trait_projections { @@ -304,8 +304,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( .. }) = item.kind { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - let opaque_identity_ty = if in_trait { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { tcx.mk_projection(def_id.to_def_id(), substs) } else { tcx.mk_opaque(def_id.to_def_id(), substs) @@ -535,7 +535,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { let trait_substs = - InternalSubsts::identity_for_item(tcx, id.owner_id.to_def_id()); + InternalSubsts::identity_for_item(tcx, id.owner_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, assoc_item, @@ -554,10 +554,18 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_union(tcx, id.owner_id.def_id); } DefKind::OpaqueTy => { - check_opaque(tcx, id); + let opaque = tcx.hir().expect_item(id.owner_id.def_id).expect_opaque_ty(); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) + && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() + { + // Skip opaques from RPIT in traits with no default body. + } else { + check_opaque(tcx, id); + } } DefKind::ImplTraitPlaceholder => { - let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id()); + let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id()); // Only check the validity of this opaque type if the function has a default body if let hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)), @@ -1161,7 +1169,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.variants().is_empty() { - if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() { + if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() { struct_span_err!( tcx.sess, attr.span, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 123207249d2..49665525967 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -330,6 +330,7 @@ fn compare_method_predicate_entailment<'tcx>( // lifetime parameters. let outlives_env = OutlivesEnvironment::with_bounds( param_env, + Some(infcx), infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()), ); infcx.process_registered_region_obligations( @@ -582,13 +583,13 @@ fn compare_asyncness<'tcx>( #[instrument(skip(tcx), level = "debug", ret)] pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + impl_m_def_id: LocalDefId, ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> { - let impl_m = tcx.opt_associated_item(def_id).unwrap(); + let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity(); - let param_env = tcx.param_env(def_id); + let param_env = tcx.param_env(impl_m_def_id); // First, check a few of the same things as `compare_impl_method`, // just so we don't ICE during substitution later. @@ -598,7 +599,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let trait_to_impl_substs = impl_trait_ref.substs; - let impl_m_def_id = impl_m.def_id.expect_local(); let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); let cause = ObligationCause::new( @@ -727,6 +727,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // lifetime parameters. let outlives_environment = OutlivesEnvironment::with_bounds( param_env, + Some(infcx), infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys), ); infcx @@ -1203,6 +1204,17 @@ fn compare_number_of_generics<'tcx>( return Ok(()); } + // We never need to emit a separate error for RPITITs, since if an RPITIT + // has mismatched type or const generic arguments, then the method that it's + // inheriting the generics from will also have mismatched arguments, and + // we'll report an error for that instead. Delay a bug for safety, though. + if tcx.opt_rpitit_info(trait_.def_id).is_some() { + return Err(tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + "errors comparing numbers of generics of trait/impl functions were not emitted", + )); + } + let matchings = [ ("type", trait_own_counts.types, impl_own_counts.types), ("const", trait_own_counts.consts, impl_own_counts.consts), @@ -2056,7 +2068,8 @@ pub(super) fn check_type_bounds<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types); - let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + let outlives_environment = + OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds); infcx.err_ctxt().check_region_obligations_and_report_errors( impl_ty.def_id.expect_local(), diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 8c364a4f3b2..1b7475486dc 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -59,6 +59,7 @@ fn equate_intrinsic_type<'tcx>( require_same_types( tcx, &cause, + ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env? tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()), fty, ); @@ -222,6 +223,21 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), + sym::option_payload_ptr => { + let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None); + let p0 = param(0); + ( + 1, + vec![tcx.mk_ptr(ty::TypeAndMut { + ty: tcx.mk_adt( + tcx.adt_def(option_def_id), + tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()), + ), + mutbl: hir::Mutability::Not, + })], + tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }), + ) + } sym::ptr_mask => ( 1, vec![ diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 9acfc1b3d29..8fe4c44fca4 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -109,8 +109,8 @@ pub fn provide(providers: &mut Providers) { }; } -fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> { - tcx.calculate_dtor(def_id, dropck::check_drop_impl) +fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> { + tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl) } /// Given a `DefId` for an opaque type in return position, find its parent item's return @@ -202,8 +202,11 @@ fn missing_items_err( missing_items: &[ty::AssocItem], full_impl_span: Span, ) { + let missing_items = + missing_items.iter().filter(|trait_item| tcx.opt_rpitit_info(trait_item.def_id).is_none()); + let missing_items_msg = missing_items - .iter() + .clone() .map(|trait_item| trait_item.name.to_string()) .collect::<Vec<_>>() .join("`, `"); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 28f0924d1d6..737532b98a4 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1,7 +1,6 @@ use crate::autoderef::Autoderef; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; -use hir::def::DefKind; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -115,7 +114,8 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( return; } - let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + let outlives_environment = + OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); let _ = infcx .err_ctxt() @@ -675,6 +675,7 @@ fn resolve_regions_with_wf_tys<'tcx>( let infcx = tcx.infer_ctxt().build(); let outlives_environment = OutlivesEnvironment::with_bounds( param_env, + Some(&infcx), infcx.implied_bounds_tys(param_env, id, wf_tys.clone()), ); let region_bound_pairs = outlives_environment.region_bound_pairs(); @@ -1546,16 +1547,27 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>( if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) && assoc_item.container == ty::AssocItemContainer::TraitContainer { + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering + // strategy, we can't just call `check_associated_item` on the new RPITITs, + // because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail. + // That's because we need to check that the bounds of the RPITIT hold using + // the special substs that we create during opaque type lowering, otherwise we're + // getting a bunch of early bound and free regions mixed up... Haven't looked too + // deep into this, though. for arg in fn_output.walk() { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, proj) = ty.kind() - && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder - && tcx.impl_trait_in_trait_parent(proj.def_id) == fn_def_id.to_def_id() + // RPITITs are always eagerly normalized into opaques, so always look for an + // opaque here. + && let ty::Alias(ty::Opaque, opaque_ty) = ty.kind() + && let Some(opaque_def_id) = opaque_ty.def_id.as_local() + && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() + && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin + && source == fn_def_id { - let span = tcx.def_span(proj.def_id); - let bounds = wfcx.tcx().explicit_item_bounds(proj.def_id); + let span = tcx.def_span(opaque_ty.def_id); + let bounds = wfcx.tcx().explicit_item_bounds(opaque_ty.def_id); let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs); + let bound = ty::EarlyBinder(bound).subst(tcx, opaque_ty.substs); let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::predicate_obligations( wfcx.infcx, @@ -1782,7 +1794,7 @@ fn check_variances_for_type_defn<'tcx>( // Lazily calculated because it is only needed in case of an error. let explicitly_bounded_params = LazyCell::new(|| { - let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id()); + let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.def_id); hir_generics .predicates .iter() diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 5e8f69677cf..25d56ea45c1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -9,15 +9,16 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::{self, RegionResolutionError}; +use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt}; +use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason, }; -use rustc_trait_selection::traits::predicate_for_trait_def; +use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCause}; use std::collections::BTreeMap; @@ -235,7 +236,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef use rustc_type_ir::sty::TyKind::*; match (source.kind(), target.kind()) { (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) - if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {} + if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok() + && mutbl_a == *mutbl_b => {} (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), (&Adt(def_a, substs_a), &Adt(def_b, substs_b)) if def_a.is_struct() && def_b.is_struct() => @@ -278,7 +280,9 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef } } - if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { + if let Ok(ok) = + infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b) + { if ok.obligations.is_empty() { create_err( "the trait `DispatchFromDyn` may only be implemented \ @@ -331,19 +335,19 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef )) .emit(); } else { - let errors = traits::fully_solve_obligations( - &infcx, - coerced_fields.into_iter().map(|field| { - predicate_for_trait_def( - tcx, - param_env, - cause.clone(), + let ocx = ObligationCtxt::new(&infcx); + for field in coerced_fields { + ocx.register_obligation(Obligation::new( + tcx, + cause.clone(), + param_env, + ty::Binder::dummy(tcx.mk_trait_ref( dispatch_from_dyn_trait, - 0, [field.ty(tcx, substs_a), field.ty(tcx, substs_b)], - ) - }), - ); + )), + )); + } + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.err_ctxt().report_fulfillment_errors(&errors); } @@ -365,11 +369,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef } } -pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { +pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> CoerceUnsizedInfo { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); - - // this provider should only get invoked for local def-ids - let impl_did = impl_did.expect_local(); let span = tcx.def_span(impl_did); let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); @@ -504,7 +505,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn // we may have to evaluate constraint // expressions in the course of execution.) // See e.g., #41936. - if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) { + if let Ok(ok) = infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, a, b) { if ok.obligations.is_empty() { return None; } @@ -580,10 +581,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn }; // Register an obligation for `A: Trait<B>`. + let ocx = ObligationCtxt::new(&infcx); let cause = traits::ObligationCause::misc(span, impl_did); - let predicate = - predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]); - let errors = traits::fully_solve_obligation(&infcx, predicate); + let obligation = + Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target])); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.err_ctxt().report_fulfillment_errors(&errors); } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 07a33bcbb50..3d37e0ce0c6 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -10,8 +10,8 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; -use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -24,7 +24,7 @@ pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { collect.impls_map } -pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, (_, simp): (CrateNum, SimplifiedType)) -> &[DefId] { +pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { let crate_map = tcx.crate_inherent_impls(()); tcx.arena.alloc_from_iter( crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()), @@ -32,9 +32,7 @@ pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, (_, simp): (CrateNum, SimplifiedT } /// On-demand query: yields a vector of the inherent impls for a specific type. -pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: DefId) -> &[DefId] { - let ty_def_id = ty_def_id.expect_local(); - +pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] { let crate_map = tcx.crate_inherent_impls(()); match crate_map.inherent_impls.get(&ty_def_id) { Some(v) => &v[..], @@ -99,12 +97,7 @@ impl<'tcx> InherentCollect<'tcx> { } } - if let Some(simp) = simplify_type( - self.tcx, - self_ty, - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) { self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); } else { bug!("unexpected self type: {:?}", self_ty); @@ -164,12 +157,7 @@ impl<'tcx> InherentCollect<'tcx> { } } - if let Some(simp) = simplify_type( - self.tcx, - ty, - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) { self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); } else { bug!("unexpected primitive type: {:?}", ty); diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 23490bc091c..465e787c92a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -133,8 +133,8 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) { check_impl(tcx, impl_def_id, trait_ref); check_object_overlap(tcx, impl_def_id, trait_ref); - tcx.sess.time("unsafety_checking", || unsafety::check_item(tcx, impl_def_id)); - tcx.sess.time("orphan_checking", || tcx.ensure().orphan_check_impl(impl_def_id)); + unsafety::check_item(tcx, impl_def_id); + tcx.ensure().orphan_check_impl(impl_def_id); } builtin::check_trait(tcx, def_id); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 604d54cafb5..c41e96290df 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -113,7 +113,7 @@ pub fn provide(providers: &mut Providers) { /// the AST (`hir::Generics`), recursively. pub struct ItemCtxt<'tcx> { tcx: TyCtxt<'tcx>, - item_def_id: DefId, + item_def_id: LocalDefId, } /////////////////////////////////////////////////////////////////////////// @@ -347,7 +347,7 @@ fn bad_placeholder<'tcx>( } impl<'tcx> ItemCtxt<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> ItemCtxt<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> { ItemCtxt { tcx, item_def_id } } @@ -356,7 +356,7 @@ impl<'tcx> ItemCtxt<'tcx> { } pub fn hir_id(&self) -> hir::HirId { - self.tcx.hir().local_def_id_to_hir_id(self.item_def_id.expect_local()) + self.tcx.hir().local_def_id_to_hir_id(self.item_def_id) } pub fn node(&self) -> hir::Node<'tcx> { @@ -370,20 +370,16 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } fn item_def_id(&self) -> DefId { - self.item_def_id + self.item_def_id.to_def_id() } fn get_type_parameter_bounds( &self, span: Span, - def_id: DefId, + def_id: LocalDefId, assoc_name: Ident, ) -> ty::GenericPredicates<'tcx> { - self.tcx.at(span).type_param_predicates(( - self.item_def_id, - def_id.expect_local(), - assoc_name, - )) + self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name)) } fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> { @@ -839,17 +835,15 @@ fn convert_variant( adt_kind, parent_did.to_def_id(), recovered, - adt_kind == AdtKind::Struct && tcx.has_attr(parent_did.to_def_id(), sym::non_exhaustive) - || variant_did.map_or(false, |variant_did| { - tcx.has_attr(variant_did.to_def_id(), sym::non_exhaustive) - }), + adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive) + || variant_did + .map_or(false, |variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)), ) } -fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> { +fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { use rustc_hir::*; - let def_id = def_id.expect_local(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let Node::Item(item) = tcx.hir().get(hir_id) else { bug!(); @@ -908,8 +902,8 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> { tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr) } -fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { - let item = tcx.hir().expect_item(def_id.expect_local()); +fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { + let item = tcx.hir().expect_item(def_id); let (is_auto, unsafety, items) = match item.kind { hir::ItemKind::Trait(is_auto, unsafety, .., items) => { @@ -1036,7 +1030,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { }); ty::TraitDef { - def_id, + def_id: def_id.to_def_id(), unsafety, paren_sugar, has_auto_impl: is_auto, @@ -1091,14 +1085,13 @@ pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir } #[instrument(level = "debug", skip(tcx))] -fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> { +fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> { use rustc_hir::Node::*; use rustc_hir::*; - let def_id = def_id.expect_local(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + let icx = ItemCtxt::new(tcx, def_id); let output = match tcx.hir().get(hir_id) { TraitItem(hir::TraitItem { @@ -1139,7 +1132,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { let abi = tcx.hir().get_foreign_abi(hir_id); - compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi) + compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) } Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => { @@ -1215,7 +1208,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( fn_sig, Applicability::MachineApplicable, ); - } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, hir_id, def_id) { + } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) { diag.span_suggestion( ty.span, "replace with an appropriate return type", @@ -1247,12 +1240,10 @@ fn infer_return_ty_for_fn_sig<'tcx>( } } -// FIXME(vincenzopalazzo): remove the hir item when the refactoring is stable fn suggest_impl_trait<'tcx>( tcx: TyCtxt<'tcx>, ret_ty: Ty<'tcx>, span: Span, - _hir_id: hir::HirId, def_id: LocalDefId, ) -> Option<String> { let format_as_assoc: fn(_, _, _, _, _) -> _ = @@ -1338,9 +1329,12 @@ fn suggest_impl_trait<'tcx>( None } -fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> { +fn impl_trait_ref( + tcx: TyCtxt<'_>, + def_id: LocalDefId, +) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> { let icx = ItemCtxt::new(tcx, def_id); - let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl(); + let impl_ = tcx.hir().expect_item(def_id).expect_impl(); impl_ .of_trait .as_ref() @@ -1380,9 +1374,9 @@ fn check_impl_constness( } } -fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity { +fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity { let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); - let item = tcx.hir().expect_item(def_id.expect_local()); + let item = tcx.hir().expect_item(def_id); match &item.kind { hir::ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(span), @@ -1465,16 +1459,16 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate fn compute_sig_of_foreign_fn_decl<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + def_id: LocalDefId, decl: &'tcx hir::FnDecl<'tcx>, abi: abi::Abi, ) -> ty::PolyFnSig<'tcx> { let unsafety = if abi == abi::Abi::RustIntrinsic { - intrinsic_operation_unsafety(tcx, def_id) + intrinsic_operation_unsafety(tcx, def_id.to_def_id()) } else { hir::Unsafety::Unsafe }; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let fty = ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None); @@ -1515,31 +1509,28 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( fty } -fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - match tcx.hir().get_if_local(def_id) { - Some(Node::ForeignItem(..)) => true, - Some(_) => false, - _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id), +fn is_foreign_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + match tcx.hir().get_by_def_id(def_id) { + Node::ForeignItem(..) => true, + _ => false, } } -fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> { - match tcx.hir().get_if_local(def_id) { - Some(Node::Expr(&rustc_hir::Expr { +fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorKind> { + match tcx.hir().get_by_def_id(def_id) { + Node::Expr(&rustc_hir::Expr { kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }), .. - })) => tcx.hir().body(body).generator_kind(), - Some(_) => None, - _ => bug!("generator_kind applied to non-local def-id {:?}", def_id), + }) => tcx.hir().body(body).generator_kind(), + _ => None, } } -fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - match tcx.hir().get_if_local(def_id) { - Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => { +fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { + match tcx.hir().get_by_def_id(def_id) { + Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => { matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) } - Some(_) => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), - _ => bug!("tried getting opaque_ty_origin for non-local def-id {:?}", def_id), + _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 127d4fa908b..119933697a1 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -5,16 +5,16 @@ use hir::{ }; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { +pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); let parent_def_id = match node { @@ -121,7 +121,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { Some(parent_def_id.to_def_id()) } Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { - Some(tcx.typeck_root_def_id(def_id)) + Some(tcx.typeck_root_def_id(def_id.to_def_id())) } // Exclude `GlobalAsm` here which cannot have generics. Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) @@ -140,7 +140,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { } } Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { - Some(tcx.typeck_root_def_id(def_id)) + Some(tcx.typeck_root_def_id(def_id.to_def_id())) } Node::Item(item) => match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { @@ -189,7 +189,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let opt_self = Some(ty::GenericParamDef { index: 0, name: kw::SelfUpper, - def_id, + def_id: def_id.to_def_id(), pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, @@ -326,7 +326,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { index: next_index(), name: Symbol::intern(arg), - def_id, + def_id: def_id.to_def_id(), pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, })); @@ -339,7 +339,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { params.push(ty::GenericParamDef { index: next_index(), name: Symbol::intern("<const_ty>"), - def_id, + def_id: def_id.to_def_id(), pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, }); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 7dce29cc0bb..aa66d7bb5ef 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -3,8 +3,8 @@ use crate::astconv::AstConv; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt}; -use rustc_span::def_id::DefId; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; /// For associated types we include both bounds written on the type @@ -16,12 +16,12 @@ use rustc_span::Span; /// `hr-associated-type-bound-1.rs`. fn associated_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, - assoc_item_def_id: DefId, + assoc_item_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { let item_ty = tcx.mk_projection( - assoc_item_def_id, + assoc_item_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); @@ -30,8 +30,8 @@ fn associated_type_bounds<'tcx>( // Associated types are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); - let trait_def_id = tcx.parent(assoc_item_def_id); - let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local()); + let trait_def_id = tcx.local_parent(assoc_item_def_id); + let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { match pred.kind().skip_binder() { @@ -45,7 +45,11 @@ fn associated_type_bounds<'tcx>( }); let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent)); - debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds); + debug!( + "associated_type_bounds({}) = {:?}", + tcx.def_path_str(assoc_item_def_id.to_def_id()), + all_bounds + ); all_bounds } @@ -56,7 +60,7 @@ fn associated_type_bounds<'tcx>( #[instrument(level = "trace", skip(tcx), ret)] fn opaque_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, - opaque_def_id: DefId, + opaque_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], item_ty: Ty<'tcx>, span: Span, @@ -74,20 +78,31 @@ fn opaque_type_bounds<'tcx>( pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, - def_id: DefId, + def_id: LocalDefId, ) -> &'_ [(ty::Predicate<'_>, Span)] { - // If the def_id is about an RPITIT, delegate explicit_item_bounds to the opaque_def_id that - // generated the synthesized associate type. - let rpitit_info = if let Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) = - tcx.opt_rpitit_info(def_id) - { - Some(opaque_def_id) - } else { - None - }; + match tcx.opt_rpitit_info(def_id.to_def_id()) { + // RPITIT's bounds are the same as opaque type bounds, but with + // a projection self type. + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item(); + let opaque_ty = item.expect_opaque_ty(); + return opaque_type_bounds( + tcx, + opaque_def_id.expect_local(), + opaque_ty.bounds, + tcx.mk_projection( + def_id.to_def_id(), + ty::InternalSubsts::identity_for_item(tcx, def_id), + ), + item.span, + ); + } + // These should have been fed! + Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(), + None => {} + } - let bounds_def_id = rpitit_info.unwrap_or(def_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(bounds_def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); match tcx.hir().get(hir_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), @@ -100,12 +115,12 @@ pub(super) fn explicit_item_bounds( .. }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - let item_ty = if *in_trait || rpitit_info.is_some() { - tcx.mk_projection(def_id, substs) + let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { + tcx.mk_projection(def_id.to_def_id(), substs) } else { - tcx.mk_opaque(def_id, substs) + tcx.mk_opaque(def_id.to_def_id(), substs) }; - opaque_type_bounds(tcx, bounds_def_id, bounds, item_ty, *span) + opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } _ => bug!("item_bounds called on {:?}", def_id), } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 2badd66e346..fdab87b6ace 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -62,15 +62,16 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic /// Returns a list of user-specified type predicates for the definition with ID `def_id`. /// N.B., this does not include any implied/inferred constraints. #[instrument(level = "trace", skip(tcx), ret)] -fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { +fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); let mut is_trait = None; let mut is_default_impl_trait = None; + // FIXME: Should ItemCtxt take a LocalDefId? let icx = ItemCtxt::new(tcx, def_id); const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty(); @@ -99,7 +100,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP | ItemKind::Union(_, generics) => generics, ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => { - is_trait = Some(ty::TraitRef::identity(tcx, def_id)); + is_trait = Some(ty::TraitRef::identity(tcx, def_id.to_def_id())); generics } ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics, @@ -253,7 +254,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } if tcx.features().generic_const_exprs { - predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local())); + predicates.extend(const_evaluatable_predicates_of(tcx, def_id)); } let mut predicates: Vec<_> = predicates.into_iter().collect(); @@ -392,18 +393,18 @@ pub(super) fn trait_explicit_predicates_and_bounds( def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { assert_eq!(tcx.def_kind(def_id), DefKind::Trait); - gather_explicit_predicates_of(tcx, def_id.to_def_id()) + gather_explicit_predicates_of(tcx, def_id) } pub(super) fn explicit_predicates_of<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + def_id: LocalDefId, ) -> ty::GenericPredicates<'tcx> { let def_kind = tcx.def_kind(def_id); if let DefKind::Trait = def_kind { // Remove bounds on associated types from the predicates, they will be // returned by `explicit_item_bounds`. - let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local()); + let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id); let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id); let is_assoc_item_ty = |ty: Ty<'tcx>| { @@ -418,7 +419,8 @@ pub(super) fn explicit_predicates_of<'tcx>( // supertrait). if let ty::Alias(ty::Projection, projection) = ty.kind() { projection.substs == trait_identity_substs - && tcx.associated_item(projection.def_id).container_id(tcx) == def_id + && tcx.associated_item(projection.def_id).container_id(tcx) + == def_id.to_def_id() } else { false } @@ -449,7 +451,7 @@ pub(super) fn explicit_predicates_of<'tcx>( } } else { if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(hir_id); if let Some(defaulted_param_def_id) = @@ -537,9 +539,9 @@ pub(super) fn explicit_predicates_of<'tcx>( /// the transitive super-predicates are converted. pub(super) fn super_predicates_of( tcx: TyCtxt<'_>, - trait_def_id: DefId, + trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { - tcx.super_predicates_that_define_assoc_type((trait_def_id, None)) + tcx.super_predicates_that_define_assoc_type((trait_def_id.to_def_id(), None)) } /// Ensures that the super-predicates of the trait with a `DefId` @@ -549,72 +551,70 @@ pub(super) fn super_predicates_that_define_assoc_type( tcx: TyCtxt<'_>, (trait_def_id, assoc_name): (DefId, Option<Ident>), ) -> ty::GenericPredicates<'_> { - if trait_def_id.is_local() { - debug!("local trait"); - let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); + let Some(trait_def_id) = trait_def_id.as_local() else { + // if `assoc_name` is None, then the query should've been redirected to an + // external provider + assert!(assoc_name.is_some()); + return tcx.super_predicates_of(trait_def_id); + }; - let Node::Item(item) = tcx.hir().get(trait_hir_id) else { - bug!("trait_node_id {} is not an item", trait_hir_id); - }; + debug!("local trait"); + let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id); - let (generics, bounds) = match item.kind { - hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits), - _ => span_bug!(item.span, "super_predicates invoked on non-trait"), - }; + let Node::Item(item) = tcx.hir().get(trait_hir_id) else { + bug!("trait_node_id {} is not an item", trait_hir_id); + }; - let icx = ItemCtxt::new(tcx, trait_def_id); + let (generics, bounds) = match item.kind { + hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits), + hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits), + _ => span_bug!(item.span, "super_predicates invoked on non-trait"), + }; - // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. - let self_param_ty = tcx.types.self_param; - let superbounds1 = if let Some(assoc_name) = assoc_name { - icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name) - } else { - icx.astconv().compute_bounds(self_param_ty, bounds) - }; + let icx = ItemCtxt::new(tcx, trait_def_id); - let superbounds1 = superbounds1.predicates(); - - // Convert any explicit superbounds in the where-clause, - // e.g., `trait Foo where Self: Bar`. - // In the case of trait aliases, however, we include all bounds in the where-clause, - // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>` - // as one of its "superpredicates". - let is_trait_alias = tcx.is_trait_alias(trait_def_id); - let superbounds2 = icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(!is_trait_alias), - assoc_name, - ); + // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. + let self_param_ty = tcx.types.self_param; + let superbounds1 = if let Some(assoc_name) = assoc_name { + icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name) + } else { + icx.astconv().compute_bounds(self_param_ty, bounds) + }; - // Combine the two lists to form the complete set of superbounds: - let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); - debug!(?superbounds); + let superbounds1 = superbounds1.predicates(); + + // Convert any explicit superbounds in the where-clause, + // e.g., `trait Foo where Self: Bar`. + // In the case of trait aliases, however, we include all bounds in the where-clause, + // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>` + // as one of its "superpredicates". + let is_trait_alias = tcx.is_trait_alias(trait_def_id.to_def_id()); + let superbounds2 = icx.type_parameter_bounds_in_generics( + generics, + item.owner_id.def_id, + self_param_ty, + OnlySelfBounds(!is_trait_alias), + assoc_name, + ); + + // Combine the two lists to form the complete set of superbounds: + let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); + debug!(?superbounds); + // Now require that immediate supertraits are converted, + // which will, in turn, reach indirect supertraits. + if assoc_name.is_none() { // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. - if assoc_name.is_none() { - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. - for &(pred, span) in superbounds { - debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = - pred.kind().skip_binder() - { - tcx.at(span).super_predicates_of(bound.def_id()); - } + for &(pred, span) in superbounds { + debug!("superbound: {:?}", pred); + if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() { + tcx.at(span).super_predicates_of(bound.def_id()); } } - - ty::GenericPredicates { parent: None, predicates: superbounds } - } else { - // if `assoc_name` is None, then the query should've been redirected to an - // external provider - assert!(assoc_name.is_some()); - tcx.super_predicates_of(trait_def_id) } + + ty::GenericPredicates { parent: None, predicates: superbounds } } /// Returns the predicates defined on `item_def_id` of the form @@ -622,7 +622,7 @@ pub(super) fn super_predicates_that_define_assoc_type( #[instrument(level = "trace", skip(tcx))] pub(super) fn type_param_predicates( tcx: TyCtxt<'_>, - (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident), + (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; @@ -637,21 +637,21 @@ pub(super) fn type_param_predicates( let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)); // Don't look for bounds where the type parameter isn't in scope. - let parent = if item_def_id == param_owner.to_def_id() { + let parent = if item_def_id == param_owner { None } else { - tcx.generics_of(item_def_id).parent + tcx.generics_of(item_def_id).parent.map(|def_id| def_id.expect_local()) }; let mut result = parent .map(|parent| { let icx = ItemCtxt::new(tcx, parent); - icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name) + icx.get_type_parameter_bounds(DUMMY_SP, def_id, assoc_name) }) .unwrap_or_default(); let mut extend = None; - let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()); + let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id); let ast_generics = match tcx.hir().get(item_hir_id) { Node::TraitItem(item) => &item.generics, @@ -673,7 +673,8 @@ pub(super) fn type_param_predicates( ItemKind::Trait(_, _, generics, ..) => { // Implied `Self: Trait` and supertrait bounds. if param_id == item_hir_id { - let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id); + let identity_trait_ref = + ty::TraitRef::identity(tcx, item_def_id.to_def_id()); extend = Some((identity_trait_ref.without_const().to_predicate(tcx), item.span)); } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 465ae047de3..f1769415797 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1051,9 +1051,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } -fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault { +fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault { debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam); - let param_def_id = param_def_id.expect_local(); let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(param_def_id) else { bug!("expected GenericParam for object_lifetime_default"); }; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index fe44fabf57d..225b1550580 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -63,7 +63,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< .find(|(_, node)| matches!(node, OwnerNode::Item(_))) .unwrap() .0 - .to_def_id(); + .def_id; let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>; let ty = item_ctxt.ast_ty_to_ty(hir_ty); @@ -244,11 +244,13 @@ fn get_path_containing_arg_in_pat<'hir>( arg_path } -pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> { +pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> { // If we are computing `type_of` the synthesized associated type for an RPITIT in the impl // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the // associated type in the impl. - if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) { + if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = + tcx.opt_rpitit_info(def_id.to_def_id()) + { match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) { Ok(map) => { let assoc_item = tcx.associated_item(def_id); @@ -263,23 +265,25 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> } } - let def_id = def_id.expect_local(); use rustc_hir::*; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + let icx = ItemCtxt::new(tcx, def_id); let output = match tcx.hir().get(hir_id) { Node::TraitItem(item) => match item.kind { TraitItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } TraitItemKind::Const(ty, body_id) => body_id .and_then(|body_id| { - is_suggestable_infer_ty(ty) - .then(|| infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant",)) + is_suggestable_infer_ty(ty).then(|| { + infer_placeholder_type( + tcx, def_id, body_id, ty.span, item.ident, "constant", + ) + }) }) .unwrap_or_else(|| icx.to_ty(ty)), TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty), @@ -290,7 +294,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> Node::ImplItem(item) => match item.kind { ImplItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } ImplItemKind::Const(ty, body_id) => { @@ -335,22 +339,23 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> } } ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty), - ItemKind::Impl(hir::Impl { self_ty, .. }) => { - match self_ty.find_self_aliases() { - spans if spans.len() > 0 => { - let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () }); - tcx.ty_error(guar) - }, - _ => icx.to_ty(*self_ty), + ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() { + spans if spans.len() > 0 => { + let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf { + span: spans.into(), + note: (), + }); + tcx.ty_error(guar) } + _ => icx.to_ty(*self_ty), }, ItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { let def = tcx.adt_def(def_id); - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { @@ -364,7 +369,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> .. }) => { if in_trait && !tcx.impl_defaultness(owner).has_value() { - span_bug!(tcx.def_span(def_id), "tried to get type of this RPITIT with no definition"); + span_bug!( + tcx.def_span(def_id), + "tried to get type of this RPITIT with no definition" + ); } find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) } @@ -387,7 +395,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> Node::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } ForeignItemKind::Static(t, _) => icx.to_ty(t), @@ -399,7 +407,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> tcx.type_of(tcx.hir().get_parent_item(hir_id)).subst_identity() } VariantData::Tuple(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } }, @@ -432,7 +440,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. }) if anon_const.hir_id == hir_id => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); substs.as_inline_const().ty() } @@ -453,15 +461,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) } - Node::TypeBinding( - TypeBinding { - hir_id: binding_id, - kind: TypeBindingKind::Equality { term: Term::Const(e) }, - ident, - .. - }, - ) if let Node::TraitRef(trait_ref) = - tcx.hir().get_parent(*binding_id) + Node::TypeBinding(TypeBinding { + hir_id: binding_id, + kind: TypeBindingKind::Equality { term: Term::Const(e) }, + ident, + .. + }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id) && e.hir_id == hir_id => { let Some(trait_def_id) = trait_ref.trait_def_id() else { @@ -475,7 +480,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> def_id.to_def_id(), ); if let Some(assoc_item) = assoc_item { - tcx.type_of(assoc_item.def_id).subst_identity() + tcx.type_of(assoc_item.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic") } else { // FIXME(associated_const_equality): add a useful error message here. tcx.ty_error_with_message( @@ -485,10 +492,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> } } - Node::TypeBinding( - TypeBinding { hir_id: binding_id, gen_args, kind, ident, .. }, - ) if let Node::TraitRef(trait_ref) = - tcx.hir().get_parent(*binding_id) + Node::TypeBinding(TypeBinding { + hir_id: binding_id, + gen_args, + kind, + ident, + .. + }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id) && let Some((idx, _)) = gen_args.args.iter().enumerate().find(|(_, arg)| { if let GenericArg::Const(ct) = arg { @@ -517,15 +527,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> }, def_id.to_def_id(), ); - if let Some(param) - = assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const()) + if let Some(assoc_item) = assoc_item + && let param = &tcx.generics_of(assoc_item.def_id).params[idx] + && matches!(param.kind, ty::GenericParamDefKind::Const { .. }) { - tcx.type_of(param.def_id).subst_identity() + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic") } else { // FIXME(associated_const_equality): add a useful error message here. tcx.ty_error_with_message( DUMMY_SP, - "Could not find associated const on trait", + "Could not find const param on associated item", ) } } @@ -593,7 +606,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T found: Option<ty::OpaqueHiddenType<'tcx>>, /// In the presence of dead code, typeck may figure out a hidden type - /// while borrowck will now. We collect these cases here and check at + /// while borrowck will not. We collect these cases here and check at /// the end that we actually found a type that matches (modulo regions). typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>, } @@ -765,7 +778,7 @@ fn find_opaque_ty_constraints_for_rpit( // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; debug!(?concrete_opaque_types); - for &(def_id, concrete_type) in concrete_opaque_types { + for (&def_id, &concrete_type) in concrete_opaque_types { if def_id != self.def_id { // Ignore constraints for other opaque types. continue; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index e330fcc7857..8269a6ddea5 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::def_id::LocalDefId; -use rustc_trait_selection::traits; +use rustc_trait_selection::traits::{self, ObligationCtxt}; pub fn provide(providers: &mut Providers) { *providers = Providers { diagnostic_hir_wf_check, ..*providers }; @@ -31,7 +31,7 @@ fn diagnostic_hir_wf_check<'tcx>( tcx.sess .delay_span_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!"); - let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + let icx = ItemCtxt::new(tcx, def_id); // To perform HIR-based WF checking, we iterate over all HIR types // that occur 'inside' the item we're checking. For example, @@ -66,35 +66,35 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { let infcx = self.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( ty.span, self.def_id, traits::ObligationCauseCode::WellFormed(None), ); - let errors = traits::fully_solve_obligation( - &infcx, - traits::Obligation::new( - self.tcx, - cause, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())), - ), - ); - if !errors.is_empty() { - debug!("Wf-check got errors for {:?}: {:?}", ty, errors); - for error in errors { - if error.obligation.predicate == self.predicate { - // Save the cause from the greatest depth - this corresponds - // to picking more-specific types (e.g. `MyStruct<u8>`) - // over less-specific types (e.g. `Option<MyStruct<u8>>`) - if self.depth >= self.cause_depth { - self.cause = Some(error.obligation.cause); - self.cause_depth = self.depth - } + + ocx.register_obligation(traits::Obligation::new( + self.tcx, + cause, + self.param_env, + ty::PredicateKind::WellFormed(tcx_ty.into()), + )); + + for error in ocx.select_all_or_error() { + debug!("Wf-check got error for {:?}: {:?}", ty, error); + if error.obligation.predicate == self.predicate { + // Save the cause from the greatest depth - this corresponds + // to picking more-specific types (e.g. `MyStruct<u8>`) + // over less-specific types (e.g. `Option<MyStruct<u8>>`) + if self.depth >= self.cause_depth { + self.cause = Some(error.obligation.cause); + self.cause_depth = self.depth } } } + self.depth += 1; intravisit::walk_ty(self, ty); self.depth -= 1; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 1c5860e97bc..7f1e4ccc964 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -168,7 +168,7 @@ fn get_impl_substs( let assumed_wf_types = ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); - let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); + let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id); let impl2_substs = translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); @@ -179,7 +179,7 @@ fn get_impl_substs( } let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types); - let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { @@ -528,7 +528,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) | ty::PredicateKind::Clause(ty::Clause::Projection(_)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 62abcbbdc9f..d43230cb563 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -102,7 +102,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::Node; -use rustc_infer::infer::{InferOk, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_macros::fluent_messages; use rustc_middle::middle; use rustc_middle::ty::query::Providers; @@ -113,7 +113,7 @@ use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt}; use std::ops::Not; @@ -160,24 +160,21 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi fn require_same_types<'tcx>( tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, -) -> bool { +) { let infcx = &tcx.infer_ctxt().build(); - let param_env = ty::ParamEnv::empty(); - let errors = match infcx.at(cause, param_env).eq(expected, actual) { - Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations), + let ocx = ObligationCtxt::new(infcx); + match ocx.eq(cause, param_env, expected, actual) { + Ok(()) => { + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors); + } + } Err(err) => { infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit(); - return false; - } - }; - - match &errors[..] { - [] => true, - errors => { - infcx.err_ctxt().report_fulfillment_errors(errors); - false } } } @@ -296,6 +293,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { return; } + // Main should have no WC, so empty param env is OK here. + let param_env = ty::ParamEnv::empty(); let expected_return_type; if let Some(term_did) = tcx.lang_items().termination() { let return_ty = main_fnsig.output(); @@ -306,8 +305,6 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let return_ty = return_ty.skip_binder(); let infcx = tcx.infer_ctxt().build(); - // Main should have no WC, so empty param env is OK here. - let param_env = ty::ParamEnv::empty(); let cause = traits::ObligationCause::new( return_ty_span, main_diagnostics_def_id, @@ -343,6 +340,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ), + param_env, se_ty, tcx.mk_fn_ptr(main_fnsig), ); @@ -417,6 +415,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { start_def_id, ObligationCauseCode::StartFunctionType, ), + ty::ParamEnv::empty(), // start should not have any where bounds. se_ty, tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()), ); @@ -513,7 +512,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id); - let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); + let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id); item_cx.astconv().ast_ty_to_ty(hir_ty) } @@ -526,7 +525,7 @@ pub fn hir_trait_to_predicates<'tcx>( // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id); - let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); + let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id); let mut bounds = Bounds::default(); let _ = &item_cx.astconv().instantiate_poly_trait_ref( hir_trait, diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 9ee6785970c..357deb07b8f 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -56,7 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::WellFormed(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 81fe32000d3..da72d2584e3 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -1,6 +1,6 @@ use hir::Node; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; @@ -17,8 +17,8 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers }; } -fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Clause<'_>, Span)] { - let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()); +fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] { + let id = tcx.hir().local_def_id_to_hir_id(item_def_id); if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() { @@ -45,7 +45,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Clause<'_ hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => { let crate_map = tcx.inferred_outlives_crate(()); - let predicates = crate_map.predicates.get(&item_def_id).copied().unwrap_or(&[]); + let predicates = + crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec<String> = predicates diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs index fa2ac56593b..60f8e246ad6 100644 --- a/compiler/rustc_hir_analysis/src/outlives/test.rs +++ b/compiler/rustc_hir_analysis/src/outlives/test.rs @@ -6,7 +6,7 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { for id in tcx.hir().items() { // For unit testing: check for a special "rustc_outlives" // attribute and report an error with various results if found. - if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_outlives) { + if tcx.has_attr(id.owner_id, sym::rustc_outlives) { let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id); struct_span_err!( tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index a8b7699b667..0a45119ff05 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -38,7 +38,7 @@ fn crate_variances(tcx: TyCtxt<'_>, (): ()) -> CrateVariancesMap<'_> { solve::solve_constraints(constraints_cx) } -fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { +fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { // Skip items with no generics - there's nothing to infer in them. if tcx.generics_of(item_def_id).count() == 0 { return &[]; @@ -53,7 +53,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { | DefKind::Variant | DefKind::Ctor(..) => {} DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => { - return variance_of_opaque(tcx, item_def_id.expect_local()); + return variance_of_opaque(tcx, item_def_id); } _ => { // Variance not relevant. @@ -64,7 +64,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { // Everything else must be inferred. let crate_map = tcx.crate_variances(()); - crate_map.variances.get(&item_def_id).copied().unwrap_or(&[]) + crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]) } #[instrument(level = "trace", skip(tcx), ret)] @@ -112,10 +112,14 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match t.kind() { ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if matches!( - self.tcx.def_kind(*def_id), - DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder - ) => + if matches!(self.tcx.def_kind(*def_id), DefKind::OpaqueTy) => + { + self.visit_opaque(*def_id, substs) + } + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) check whether this is necessary + // at all for RPITITs. + ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + if self.tcx.is_impl_trait_in_trait(*def_id) => { self.visit_opaque(*def_id, substs) } @@ -148,7 +152,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc let mut collector = OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances }; - let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id()); + let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id); for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() { let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); debug!(?pred); diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs index 64614831f56..d57d05d7605 100644 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ b/compiler/rustc_hir_analysis/src/variance/test.rs @@ -7,7 +7,7 @@ pub fn test_variance(tcx: TyCtxt<'_>) { // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. for id in tcx.hir().items() { - if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) { + if tcx.has_attr(id.owner_id, sym::rustc_variance) { let variances_of = tcx.variances_of(id.owner_id); tcx.sess.emit_err(errors::VariancesOf { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d715b03e40e..63ea6c90477 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1366,10 +1366,6 @@ impl<'a> State<'a> { self.ibox(INDENT_UNIT); self.ann.pre(self, AnnNode::Expr(expr)); match expr.kind { - hir::ExprKind::Box(expr) => { - self.word_space("Box::new"); - self.print_call_post(std::slice::from_ref(expr)); - } hir::ExprKind::Array(exprs) => { self.print_expr_vec(exprs); } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index e19ef2ff3bf..035ccf30b24 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -299,7 +299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // check that the `if` expr without `else` is the fn body's expr if expr.span == sp { - return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| { + return self.get_fn_decl(hir_id).and_then(|(_, fn_decl, _)| { let span = fn_decl.output.span(); let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?; Some((span, format!("expected `{snippet}` because of this return type"))) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index ecbe4a97dd9..5235710a266 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty) - && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span) + && !self.type_is_sized_modulo_regions(self.param_env, output_ty) { let descr = match maybe_def { DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id), diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 316c2a7eeeb..d28b3b3ce7b 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -96,7 +96,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let t = self.resolve_vars_if_possible(t); t.error_reported()?; - if self.type_is_sized_modulo_regions(self.param_env, t, span) { + if self.type_is_sized_modulo_regions(self.param_env, t) { return Ok(Some(PointerKind::Thin)); } @@ -722,7 +722,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); - if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span) + if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty) && !self.cast_ty.has_infer_types() { self.report_cast_to_unsized_type(fcx); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 773ac0e40c5..ec391ea80f4 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -2,13 +2,12 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; -use hir::def::DefKind; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_infer::infer::{DefineOpaqueTypes, LateBoundRegionConversionTime}; use rustc_infer::infer::{InferOk, InferResult}; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::ty::subst::InternalSubsts; @@ -563,10 +562,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { // Check that E' = S'. let cause = self.misc(hir_ty.span); - let InferOk { value: (), obligations } = self - .at(&cause, self.param_env) - .define_opaque_types(true) - .eq(*expected_ty, supplied_ty)?; + let InferOk { value: (), obligations } = self.at(&cause, self.param_env).eq( + DefineOpaqueTypes::Yes, + *expected_ty, + supplied_ty, + )?; all_obligations.extend(obligations); } @@ -576,10 +576,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { supplied_sig.output(), ); let cause = &self.misc(decl.output.span()); - let InferOk { value: (), obligations } = self - .at(cause, self.param_env) - .define_opaque_types(true) - .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; + let InferOk { value: (), obligations } = self.at(cause, self.param_env).eq( + DefineOpaqueTypes::Yes, + expected_sigs.liberated_sig.output(), + supplied_output_ty, + )?; all_obligations.extend(obligations); let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty)); @@ -713,14 +714,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .subst_iter_copied(self.tcx, substs) .find_map(|(p, s)| get_future_output(p, s))?, ty::Error(_) => return None, - ty::Alias(ty::Projection, proj) - if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder => - { - self.tcx - .bound_explicit_item_bounds(proj.def_id) - .subst_iter_copied(self.tcx, proj.substs) - .find_map(|(p, s)| get_future_output(p, s))? - } + ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self + .tcx + .bound_explicit_item_bounds(proj.def_id) + .subst_iter_copied(self.tcx, proj.substs) + .find_map(|(p, s)| get_future_output(p, s))?, _ => span_bug!( self.tcx.def_span(expr_def_id), "async fn generator return type not an inference variable: {ret_ty}" diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 00b86890b33..8fa3bcd68c3 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -45,8 +45,8 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Expr; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{Coercion, InferOk, InferResult}; -use rustc_infer::traits::Obligation; +use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; +use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, @@ -143,11 +143,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|_| { - let at = self.at(&self.cause, self.fcx.param_env).define_opaque_types(true); + let at = self.at(&self.cause, self.fcx.param_env); if self.use_lub { - at.lub(b, a) + at.lub(DefineOpaqueTypes::Yes, b, a) } else { - at.sup(b, a) + at.sup(DefineOpaqueTypes::Yes, b, a) .map(|InferOk { value: (), obligations }| InferOk { value: a, obligations }) } }) @@ -175,7 +175,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // so this will have the side-effect of making sure we have no ambiguities // due to `[type error]` and `_` not coercing together. let _ = self.commit_if_ok(|_| { - self.at(&self.cause, self.param_env).define_opaque_types(true).eq(a, b) + self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b) }); return success(vec![], self.fcx.tcx.ty_error(guar), vec![]); } @@ -597,13 +597,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // and almost never more than 3. By using a SmallVec we avoid an // allocation, at the (very small) cost of (occasionally) having to // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def( + let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new( self.tcx, - self.fcx.param_env, cause, - coerce_unsized_did, - 0, - [coerce_source, coerce_target] + self.fcx.param_env, + self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target]) )]; let mut has_unsized_tuple_coercion = false; @@ -651,9 +649,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let self_ty = trait_pred.skip_binder().self_ty(); let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); - match (&self_ty.kind(), &unsize_ty.kind()) { - (ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) - if self.type_var_is_sized(*v) => + match (self_ty.kind(), unsize_ty.kind()) { + (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) + if self.type_var_is_sized(v) => { debug!("coerce_unsized: have sized infer {:?}", v); coercion.obligations.push(obligation); @@ -1101,9 +1099,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (ty::FnDef(..), ty::FnDef(..)) => { // Don't reify if the function types have a LUB, i.e., they // are the same function and their parameters have a LUB. - match self - .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) - { + match self.commit_if_ok(|_| { + self.at(cause, self.param_env).lub( + DefineOpaqueTypes::No, + prev_ty, + new_ty, + ) + }) { // We have a LUB of prev_ty and new_ty, just return it. Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), Err(_) => { @@ -1153,7 +1155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sig = self .at(cause, self.param_env) .trace(prev_ty, new_ty) - .lub(a_sig, b_sig) + .lub(DefineOpaqueTypes::No, a_sig, b_sig) .map(|ok| self.register_infer_ok_obligations(ok))?; // Reify both sides and return the reified fn pointer type. @@ -1237,7 +1239,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return self - .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) + .commit_if_ok(|_| { + self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty) + }) .map(|ok| self.register_infer_ok_obligations(ok)); } } @@ -1248,8 +1252,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(e) = first_error { Err(e) } else { - self.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) - .map(|ok| self.register_infer_ok_obligations(ok)) + self.commit_if_ok(|_| { + self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty) + }) + .map(|ok| self.register_infer_ok_obligations(ok)) } } Ok(ok) => { @@ -1487,8 +1493,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { assert!(expression_ty.is_unit(), "if let hack without unit type"); fcx.at(cause, fcx.param_env) // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs - .define_opaque_types(true) - .eq_exp(label_expression_as_expected, expression_ty, self.merged_ty()) + .eq_exp( + DefineOpaqueTypes::Yes, + label_expression_as_expected, + expression_ty, + self.merged_ty(), + ) .map(|infer_ok| { fcx.register_infer_ok_obligations(infer_ok); expression_ty @@ -1710,12 +1720,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.suggest_semicolon_at_end(cond_expr.span, &mut err); } } - fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) + fcx.get_node_fn_decl(parent) + .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main)) } else { fcx.get_fn_decl(parent_id) }; - if let Some((fn_decl, can_suggest)) = fn_decl { + if let Some((fn_id, fn_decl, can_suggest)) = fn_decl { if blk_id.is_none() { pointing_at_return_type |= fcx.suggest_missing_return_type( &mut err, @@ -1723,7 +1734,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expected, found, can_suggest, - fcx.tcx.hir().get_parent_item(id).into(), + fn_id, ); } if !pointing_at_return_type { @@ -1734,17 +1745,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let parent_id = fcx.tcx.hir().get_parent_item(id); let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id); - if let (Some(expr), Some(_), Some((fn_decl, _, _))) = + if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) = (expression, blk_id, fcx.get_node_fn_decl(parent_item)) { fcx.suggest_missing_break_or_return_expr( - &mut err, - expr, - fn_decl, - expected, - found, - id, - parent_id.into(), + &mut err, expr, fn_decl, expected, found, id, fn_id, ); } @@ -1870,7 +1875,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { - if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) + if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id) && let hir::FnRetTy::Return(ty) = fn_decl.output && let ty = fcx.astconv().ast_ty_to_ty( ty) && let ty::Dynamic(..) = ty.kind() diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 0ec10dc9ea3..4846579b980 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -8,7 +8,7 @@ use rustc_hir::def::CtorKind; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; -use rustc_infer::infer::InferOk; +use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::adjustment::AllowTwoPhase; @@ -113,7 +113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - match self.at(cause, self.param_env).define_opaque_types(true).sup(expected, actual) { + match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); None @@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - match self.at(cause, self.param_env).define_opaque_types(true).eq(expected, actual) { + match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); None @@ -1480,14 +1480,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // For this suggestion to make sense, the type would need to be `Copy`, // or we have to be moving out of a `Box<T>` - if self.type_is_copy_modulo_regions(self.param_env, expected, sp) + if self.type_is_copy_modulo_regions(self.param_env, expected) // FIXME(compiler-errors): We can actually do this if the checked_ty is // `steps` layers of boxes, not just one, but this is easier and most likely. || (checked_ty.is_box() && steps == 1) { let deref_kind = if checked_ty.is_box() { "unboxing the value" - } else if checked_ty.is_region_ptr() { + } else if checked_ty.is_ref() { "dereferencing the borrow" } else { "dereferencing the type" diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7fc4ccb04ee..fb7cb86d734 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -36,6 +36,7 @@ use rustc_hir_analysis::astconv::AstConv as _; use rustc_hir_analysis::check::ty_kind_suggestion; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::InferOk; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability; @@ -230,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = ensure_sufficient_stack(|| match &expr.kind { hir::ExprKind::Path( - qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..), + qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), ) => self.check_expr_path(qpath, expr, args), _ => self.check_expr_kind(expr, expected), }); @@ -283,7 +284,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; match expr.kind { - ExprKind::Box(subexpr) => self.check_expr_box(subexpr, expected), ExprKind::Lit(ref lit) => self.check_lit(&lit, expected), ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected), ExprKind::Assign(lhs, rhs, span) => { @@ -358,16 +358,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_expr_box(&self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>) -> Ty<'tcx> { - let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind() { - ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()), - _ => NoExpectation, - }); - let referent_ty = self.check_expr_with_expectation(expr, expected_inner); - self.require_type_is_sized(referent_ty, expr.span, traits::SizedBoxType); - self.tcx.mk_box(referent_ty) - } - fn check_expr_unary( &self, unop: hir::UnOp, @@ -798,7 +788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.ret_coercion_span.set(Some(expr.span)); } let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) { + if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) { coercion.coerce_forced_unit( self, &cause, @@ -1683,7 +1673,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(_) = remaining_fields.remove(&ident) { let target_ty = self.field_ty(base_expr.span, f, substs); let cause = self.misc(base_expr.span); - match self.at(&cause, self.param_env).sup(target_ty, fru_ty) { + match self.at(&cause, self.param_env).sup( + DefineOpaqueTypes::No, + target_ty, + fru_ty, + ) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations) } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index b9a058d6bba..c62c1553d6f 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -356,10 +356,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.walk_captures(closure); } - hir::ExprKind::Box(ref base) => { - self.consume_expr(base); - } - hir::ExprKind::Yield(value, _) => { self.consume_expr(value); } @@ -871,10 +867,7 @@ fn copy_or_move<'a, 'tcx>( mc: &mc::MemCategorizationContext<'a, 'tcx>, place_with_id: &PlaceWithHirId<'tcx>, ) -> ConsumeMode { - if !mc.type_is_copy_modulo_regions( - place_with_id.place.ty(), - mc.tcx().hir().span(place_with_id.hir_id), - ) { + if !mc.type_is_copy_modulo_regions(place_with_id.place.ty()) { ConsumeMode::Move } else { ConsumeMode::Copy diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ac73cd7cc6e..3def97bca47 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -19,7 +19,7 @@ use rustc_hir_analysis::astconv::{ }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc_infer::infer::InferResult; +use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; @@ -558,7 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = self.tcx.hir().body(body_id).value.span; let ok = self .at(&self.misc(span), self.param_env) - .eq(interior, witness) + .eq(DefineOpaqueTypes::No, interior, witness) .expect("Failed to unify generator interior type"); let mut obligations = ok.obligations; @@ -666,7 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) // N.B., this predicate is created by breaking down a @@ -898,51 +898,74 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } - /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. + /// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure + /// that is the child of a function, return that function's `HirId` and `FnDecl` instead. + /// This may seem confusing at first, but this is used in diagnostics for `async fn`, + /// for example, where most of the type checking actually happens within a nested closure, + /// but we often want access to the parent function's signature. + /// + /// Otherwise, return false. pub(in super::super) fn get_node_fn_decl( &self, node: Node<'tcx>, - ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { + ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> { match node { - Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { + Node::Item(&hir::Item { + ident, + kind: hir::ItemKind::Fn(ref sig, ..), + owner_id, + .. + }) => { // 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)) + Some(( + hir::HirId::make_owner(owner_id.def_id), + &sig.decl, + ident, + ident.name != sym::main, + )) } Node::TraitItem(&hir::TraitItem { ident, kind: hir::TraitItemKind::Fn(ref sig, ..), + owner_id, .. - }) => Some((&sig.decl, ident, true)), + }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)), Node::ImplItem(&hir::ImplItem { ident, kind: hir::ImplItemKind::Fn(ref sig, ..), + owner_id, .. - }) => Some((&sig.decl, ident, false)), - Node::Expr(&hir::Expr { - hir_id, - kind: hir::ExprKind::Closure(..), - .. - }) if let Some(Node::Item(&hir::Item { + }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)), + Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. }) + if let Some(Node::Item(&hir::Item { + ident, + kind: hir::ItemKind::Fn(ref sig, ..), + owner_id, + .. + })) = self.tcx.hir().find_parent(hir_id) => Some(( + hir::HirId::make_owner(owner_id.def_id), + &sig.decl, ident, - kind: hir::ItemKind::Fn(ref sig, ..), - .. - })) = self.tcx.hir().find_parent(hir_id) => { - Some((&sig.decl, ident, ident.name != sym::main)) - }, + ident.name != sym::main, + )), _ => None, } } - /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a + /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, 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)> { + pub fn get_fn_decl( + &self, + blk_id: hir::HirId, + ) -> Option<(hir::HirId, &'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)) + self.get_node_fn_decl(parent) + .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main)) }) } @@ -1341,7 +1364,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This also occurs for an enum variant on a type alias. let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).subst(tcx, substs)); let self_ty = self.normalize(span, self_ty); - match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) { + match self.at(&self.misc(span), self.param_env).eq( + DefineOpaqueTypes::No, + impl_ty, + self_ty, + ) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { self.tcx.sess.delay_span_bug( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index ec14bd3c6f4..7534e432f11 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -4,7 +4,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{self, Span}; +use rustc_span::{self, symbol::kw, Span}; use rustc_trait_selection::traits; use std::ops::ControlFlow; @@ -25,17 +25,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(def_id); let predicate_substs = match unsubstituted_pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs, - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs, - _ => ty::List::empty(), + ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(), + ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + pred.projection_ty.substs.to_vec() + } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => { + vec![ty.into(), arg.into()] + } + ty::PredicateKind::ConstEvaluatable(e) => vec![e.into()], + _ => return false, }; - let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| { - predicate_substs.types().find_map(|ty| { - ty.walk().find_map(|arg| { + let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| { + predicate_substs.iter().find_map(|arg| { + arg.walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Param(param_ty) = ty.kind() - && matches(param_ty) + && let ty::Param(param_ty) = *ty.kind() + && matches(ty::ParamTerm::Ty(param_ty)) + { + Some(arg) + } else if let ty::GenericArgKind::Const(ct) = arg.unpack() + && let ty::ConstKind::Param(param_ct) = ct.kind() + && matches(ty::ParamTerm::Const(param_ct)) { Some(arg) } else { @@ -47,21 +58,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Prefer generics that are local to the fn item, since these are likely // to be the cause of the unsatisfied predicate. - let mut param_to_point_at = find_param_matching(&|param_ty| { - self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id + let mut param_to_point_at = find_param_matching(&|param_term| { + self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id }); // Fall back to generic that isn't local to the fn item. This will come // from a trait or impl, for example. - let mut fallback_param_to_point_at = find_param_matching(&|param_ty| { - self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id - && param_ty.name != rustc_span::symbol::kw::SelfUpper + let mut fallback_param_to_point_at = find_param_matching(&|param_term| { + self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id + && !matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper) }); // Finally, the `Self` parameter is possibly the reason that the predicate // is unsatisfied. This is less likely to be true for methods, because // method probe means that we already kinda check that the predicates due // to the `Self` type are true. - let mut self_param_to_point_at = - find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper); + let mut self_param_to_point_at = find_param_matching( + &|param_term| matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper), + ); // Finally, for ambiguity-related errors, we actually want to look // for a parameter that is the source of the inference type left @@ -225,14 +237,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); let Some((index, _)) = own_substs .iter() - .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_))) .enumerate() .find(|(_, arg)| **arg == param_to_point_at) else { return false }; let Some(arg) = segment .args() .args .iter() - .filter(|arg| matches!(arg, hir::GenericArg::Type(_))) .nth(index) else { return false; }; error.obligation.cause.span = arg .span() @@ -300,7 +310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .filter(|field| { let field_ty = field.ty(self.tcx, identity_substs); - Self::find_param_in_ty(field_ty.into(), param_to_point_at) + find_param_in_ty(field_ty.into(), param_to_point_at) }) .collect(); @@ -346,7 +356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .inputs() .iter() .enumerate() - .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at)) + .filter(|(_, ty)| find_param_in_ty((**ty).into(), param_to_point_at)) .collect(); // If there's one field that references the given generic, great! if let [(idx, _)] = args_referencing_param.as_slice() @@ -569,8 +579,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find out which of `in_ty_elements` refer to `param`. // FIXME: It may be better to take the first if there are multiple, // just so that the error points to a smaller expression. - let Some((drill_expr, drill_ty)) = Self::is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| { - Self::find_param_in_ty((*in_ty_elem).into(), param) + let Some((drill_expr, drill_ty)) = is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| { + find_param_in_ty((*in_ty_elem).into(), param) })) else { // The param is not mentioned, or it is mentioned in multiple indexes. return Err(expr); @@ -618,10 +628,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We need to know which of the generic parameters mentions our target param. // We expect that at least one of them does, since it is expected to be mentioned. let Some((drill_generic_index, generic_argument_type)) = - Self::is_iterator_singleton( + is_iterator_singleton( in_ty_adt_generic_args.iter().enumerate().filter( |(_index, in_ty_generic)| { - Self::find_param_in_ty(*in_ty_generic, param) + find_param_in_ty(*in_ty_generic, param) }, ), ) else { @@ -741,10 +751,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We need to know which of the generic parameters mentions our target param. // We expect that at least one of them does, since it is expected to be mentioned. let Some((drill_generic_index, generic_argument_type)) = - Self::is_iterator_singleton( + is_iterator_singleton( in_ty_adt_generic_args.iter().enumerate().filter( |(_index, in_ty_generic)| { - Self::find_param_in_ty(*in_ty_generic, param) + find_param_in_ty(*in_ty_generic, param) }, ), ) else { @@ -783,14 +793,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // outer contextual information. // (1) Find the (unique) field index which mentions the type in our constraint: - let Some((field_index, field_type)) = Self::is_iterator_singleton( + let Some((field_index, field_type)) = is_iterator_singleton( in_ty_adt .variant_with_id(variant_def_id) .fields .iter() .map(|field| field.ty(self.tcx, *in_ty_adt_generic_args)) .enumerate() - .filter(|(_index, field_type)| Self::find_param_in_ty((*field_type).into(), param)) + .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)) ) else { return Err(expr); }; @@ -823,20 +833,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(expr) } +} - // FIXME: This can be made into a private, non-impl function later. - /// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references - /// to the given `param_to_point_at`. Returns `true` if it finds any use of the param. - pub fn find_param_in_ty( - ty: ty::GenericArg<'tcx>, - param_to_point_at: ty::GenericArg<'tcx>, - ) -> bool { - let mut walk = ty.walk(); - while let Some(arg) = walk.next() { - if arg == param_to_point_at { - return true; - } - if let ty::GenericArgKind::Type(ty) = arg.unpack() +/// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references +/// to the given `param_to_point_at`. Returns `true` if it finds any use of the param. +fn find_param_in_ty<'tcx>( + ty: ty::GenericArg<'tcx>, + param_to_point_at: ty::GenericArg<'tcx>, +) -> bool { + let mut walk = ty.walk(); + while let Some(arg) = walk.next() { + if arg == param_to_point_at { + return true; + } + if let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Alias(ty::Projection, ..) = ty.kind() { // This logic may seem a bit strange, but typically when @@ -847,16 +857,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in some UI tests. walk.skip_current_subtree(); } - } - false } + false +} - // FIXME: This can be made into a private, non-impl function later. - /// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise. - pub fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> { - match (iterator.next(), iterator.next()) { - (_, Some(_)) => None, - (first, _) => first, - } +/// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise. +fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> { + match (iterator.next(), iterator.next()) { + (_, Some(_)) => None, + (first, _) => first, } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ea54b76bdec..61338ac613a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -24,8 +24,8 @@ use rustc_hir_analysis::structured_errors::StructuredDiagnostic; use rustc_index::vec::IndexVec; use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::InferOk; use rustc_infer::infer::TypeTrace; +use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, IsSuggestable, Ty}; @@ -301,9 +301,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 3. Check if the formal type is a supertype of the checked one // and register any such obligations for future type checks - let supertype_error = self - .at(&self.misc(provided_arg.span), self.param_env) - .sup(formal_input_ty, coerced_ty); + let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup( + DefineOpaqueTypes::No, + formal_input_ty, + coerced_ty, + ); let subtyping_error = match supertype_error { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); @@ -585,7 +587,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Using probe here, since we don't want this subtyping to affect inference. let subtyping_error = self.probe(|_| { - self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err() + self.at(&self.misc(arg_span), self.param_env) + .sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty) + .err() }); // Same as above: if either the coerce type or the checked type is an error type, @@ -1665,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 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_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id); - self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) + 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 diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 1dea3e6f900..c6fd0b61035 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -211,13 +211,13 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn get_type_parameter_bounds( &self, _: Span, - def_id: DefId, + def_id: LocalDefId, _: Ident, ) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; - let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); + let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; ty::GenericPredicates { parent: None, predicates: tcx.arena.alloc_from_iter( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index aa8767fc85c..5fda4e191c2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -64,8 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr = expr.peel_drop_temps(); self.suggest_missing_semicolon(err, expr, expected, false); let mut pointing_at_return_type = false; - if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { - let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap(); + if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { pointing_at_return_type = self.suggest_missing_return_type( err, &fn_decl, @@ -166,8 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> { - let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); - self.err_ctxt().extract_callable_info(body_hir_id, self.param_env, ty) + self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty) } pub fn suggest_two_fn_call( @@ -1017,11 +1015,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut suggest_copied_or_cloned = || { let expr_inner_ty = substs.type_at(0); let expected_inner_ty = expected_substs.type_at(0); - if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() - && self.can_eq(self.param_env, *ty, expected_inner_ty) + if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() + && self.can_eq(self.param_env, ty, expected_inner_ty) { let def_path = self.tcx.def_path_str(adt_def.did()); - if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) { + if self.type_is_copy_modulo_regions(self.param_env, ty) { diag.span_suggestion_verbose( expr.span.shrink_to_hi(), format!( @@ -1035,9 +1033,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( self, self.param_env, - *ty, + ty, clone_did, - expr.span ) { diag.span_suggestion_verbose( diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 7c0402b1c7f..1eeb7d984ee 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -190,7 +190,6 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { // // Some of these may be interesting in the future ExprKind::Path(..) - | ExprKind::Box(..) | ExprKind::ConstBlock(..) | ExprKind::Array(..) | ExprKind::Call(..) @@ -478,7 +477,6 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { | ExprKind::AssignOp(..) | ExprKind::Binary(..) | ExprKind::Block(..) - | ExprKind::Box(..) | ExprKind::Cast(..) | ExprKind::Closure { .. } | ExprKind::ConstBlock(..) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 2e41c2041f8..9ecc870a70d 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; -use rustc_infer::infer::RegionVariableOrigin; +use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin}; use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData}; use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitableExt}; @@ -327,7 +327,11 @@ pub fn resolve_interior<'a, 'tcx>( ); // Unify the type variable inside the generator with the new witness - match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(interior, witness) { + match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq( + DefineOpaqueTypes::No, + interior, + witness, + ) { Ok(ok) => fcx.register_infer_ok_obligations(ok), _ => bug!("failed to relate {interior} and {witness}"), } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d9c56134b66..6af095cb4d4 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -207,7 +207,7 @@ fn typeck_with_fallback<'tcx>( let body = tcx.hir().body(body_id); let param_env = tcx.param_env(def_id); - let param_env = if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) { + let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) { param_env.without_const() } else { param_env diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 4d3969d28aa..95e5483abf3 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -120,8 +120,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.infcx.tcx } - pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { - self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) + pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.infcx.type_is_copy_modulo_regions(self.param_env, ty) } fn resolve_vars_if_possible<T>(&self, value: T) -> T @@ -382,7 +382,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)), } } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 169f128e0a0..a0aa43deadc 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -8,7 +8,7 @@ use rustc_hir_analysis::astconv::generics::{ check_generic_arg_count_for_call, create_substs_for_generic_args, }; use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall}; -use rustc_infer::infer::{self, InferOk}; +use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; @@ -478,7 +478,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { substs, })), ); - match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) { + match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3254a930342..dab709e17f0 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -13,9 +13,9 @@ use rustc_hir_analysis::astconv::InferCtxtExt as _; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; -use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; @@ -700,7 +700,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) { - let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey, TreatProjections::AsCandidateKey) else { + let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else { bug!("unexpected incoherent type: {:?}", self_ty) }; for &impl_def_id in self.tcx.incoherent_impls(simp) { @@ -837,7 +837,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, } }); @@ -930,7 +930,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if let Some(self_ty) = self_ty { if self .at(&ObligationCause::dummy(), self.param_env) - .sup(fty.inputs()[0], self_ty) + .sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty) .is_err() { return false; @@ -1027,6 +1027,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { true } }) + // ensure that we don't suggest unstable methods + .filter(|candidate| { + // note that `DUMMY_SP` is ok here because it is only used for + // suggestions and macro stuff which isn't applicable here. + !matches!( + self.tcx.eval_stability(candidate.item.def_id, None, DUMMY_SP, None), + stability::EvalResult::Deny { .. } + ) + }) .map(|candidate| candidate.item.ident(self.tcx)) .filter(|&name| set.insert(name)) .collect(); @@ -1436,9 +1445,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { CandidateSource::Trait(candidate.item.container_id(self.tcx)) } TraitCandidate(trait_ref) => self.probe(|_| { - let _ = self - .at(&ObligationCause::dummy(), self.param_env) - .sup(candidate.xform_self_ty, self_ty); + let _ = self.at(&ObligationCause::dummy(), self.param_env).sup( + DefineOpaqueTypes::No, + candidate.xform_self_ty, + self_ty, + ); match self.select_trait_candidate(trait_ref) { Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { // If only a single impl matches, make the error message point @@ -1465,10 +1476,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.probe(|_| { // First check that the self type can be related. - let sub_obligations = match self - .at(&ObligationCause::dummy(), self.param_env) - .sup(probe.xform_self_ty, self_ty) - { + let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup( + DefineOpaqueTypes::No, + probe.xform_self_ty, + self_ty, + ) { Ok(InferOk { obligations, value: () }) => obligations, Err(err) => { debug!("--> cannot relate self-types {:?}", err); @@ -1683,7 +1695,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if let ProbeResult::Match = result && self .at(&ObligationCause::dummy(), self.param_env) - .sup(return_ty, xform_ret_ty) + .sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty) .is_err() { result = ProbeResult::BadReturnType; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 50f2b71250c..55f684599e7 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -25,7 +25,6 @@ use rustc_infer::infer::{ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::util::supertraits; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths}; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt}; @@ -1182,7 +1181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .inputs() .skip_binder() .get(0) - .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr()) + .filter(|ty| ty.is_ref() && !rcvr_ty.is_ref()) .copied() .unwrap_or(rcvr_ty), }; @@ -1524,7 +1523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .any(|info| self.associated_value(info.def_id, item_name).is_some()); let found_assoc = |ty: Ty<'tcx>| { - simplify_type(tcx, ty, TreatParams::AsCandidateKey, TreatProjections::AsCandidateKey) + simplify_type(tcx, ty, TreatParams::AsCandidateKey) .and_then(|simp| { tcx.incoherent_impls(simp) .iter() @@ -2653,12 +2652,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: Even though negative bounds are not implemented, we could maybe handle // cases where a positive bound implies a negative impl. (candidates, Vec::new()) - } else if let Some(simp_rcvr_ty) = simplify_type( - self.tcx, - rcvr_ty, - TreatParams::ForLookup, - TreatProjections::ForLookup, - ) { + } else if let Some(simp_rcvr_ty) = + simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup) + { let mut potential_candidates = Vec::new(); let mut explicitly_negative = Vec::new(); for candidate in candidates { @@ -2671,12 +2667,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .any(|imp_did| { let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity(); - let imp_simp = simplify_type( - self.tcx, - imp.self_ty(), - TreatParams::ForLookup, - TreatProjections::ForLookup, - ); + let imp_simp = + simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup); imp_simp.map_or(false, |s| s == simp_rcvr_ty) }) { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 37783bc91bb..8a83bb58573 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -21,7 +21,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, FulfillmentError}; +use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; use rustc_type_ir::sty::TyKind::*; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -434,7 +434,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.type_is_copy_modulo_regions( self.param_env, *lhs_deref_ty, - lhs_expr.span, ) { suggest_deref_binop(*lhs_deref_ty); } @@ -776,7 +775,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, Some(trait_did)) => { let (obligation, _) = self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); - Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation)) + // FIXME: This should potentially just add the obligation to the `FnCtxt` + let ocx = ObligationCtxt::new(&self.infcx); + ocx.register_obligation(obligation); + Err(ocx.select_all_or_error()) } } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 11ff65d0c37..c36c75e4443 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -238,8 +238,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Note that there are two tests to check that this remains true // (`regions-reassign-{match,let}-bound-pointer.rs`). // - // 2. An outdated issue related to the old HIR borrowck. See the test + // 2. Things go horribly wrong if we use subtype. The reason for + // THIS is a fairly subtle case involving bound regions. See the + // `givens` field in `region_constraints`, as well as the test // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, + // for details. Short version is that we must sometimes detect + // relationships between specific region variables and regions + // bound in a closure signature, and that detection gets thrown + // off when we substitute fresh region variables here to enable + // subtyping. } /// Compute the new expected type and default binding mode from the old ones diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4a432328c4d..eadc30a799b 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // closures. We want to make sure any adjustment that might make us move the place into // the closure gets handled. let (place, capture_kind) = - restrict_precision_for_drop_types(self, place, capture_kind, usage_span); + restrict_precision_for_drop_types(self, place, capture_kind); capture_info.capture_kind = capture_kind; (place, capture_info) @@ -712,10 +712,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - unreachable!( - "we captured two identical projections: capture1 = {:?}, capture2 = {:?}", - capture1, capture2 + self.tcx.sess.delay_span_bug( + closure_span, + &format!( + "two identical projections: ({:?}, {:?})", + capture1.place.projections, capture2.place.projections + ), ); + std::cmp::Ordering::Equal }); } @@ -1498,7 +1502,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool { - self.tcx.has_attr(closure_def_id.to_def_id(), sym::rustc_capture_analysis) + self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis) } fn log_capture_analysis_first_pass( @@ -1822,9 +1826,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>( fcx: &'a FnCtxt<'a, 'tcx>, mut place: Place<'tcx>, mut curr_mode: ty::UpvarCapture, - span: Span, ) -> (Place<'tcx>, ty::UpvarCapture) { - let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span); + let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty()); if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) { for i in 0..place.projections.len() { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index af588b16d59..e876fa27593 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -44,8 +44,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This attribute causes us to dump some writeback information // in the form of errors, which is used for unit tests. - let rustc_dump_user_substs = - self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_dump_user_substs); + let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); for param in body.params { diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index b839416c919..1d88dfd20c8 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -371,7 +371,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { fn check_item(&mut self, item_id: LocalDefId) { let item_span = self.tcx.def_span(item_id.to_def_id()); let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id()); - for attr in self.tcx.get_attrs(item_id.to_def_id(), sym::rustc_clean) { + for attr in self.tcx.get_attrs(item_id, sym::rustc_clean) { let Some(assertion) = self.assertion_maybe(item_id, attr) else { continue; }; diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 4deae9f41c7..d6f83838a04 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -108,7 +108,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::{base_n, flock}; use rustc_errors::ErrorGuaranteed; -use rustc_fs_util::{link_or_copy, LinkOrCopy}; +use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy}; use rustc_session::{Session, StableCrateId}; use rustc_span::Symbol; @@ -223,7 +223,7 @@ pub fn prepare_session_directory( // because, on windows, long paths can cause problems; // canonicalization inserts this weird prefix that makes windows // tolerate long paths. - let crate_dir = match crate_dir.canonicalize() { + let crate_dir = match try_canonicalize(&crate_dir) { Ok(v) => v, Err(err) => { return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err })); @@ -867,7 +867,7 @@ fn all_except_most_recent( /// before passing it to std::fs::remove_dir_all(). This will convert the path /// into the '\\?\' format, which supports much longer paths. fn safe_remove_dir_all(p: &Path) -> io::Result<()> { - let canonicalized = match std_fs::canonicalize(p) { + let canonicalized = match try_canonicalize(p) { Ok(canonicalized) => canonicalized, Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), Err(err) => return Err(err), @@ -877,7 +877,7 @@ fn safe_remove_dir_all(p: &Path) -> io::Result<()> { } fn safe_remove_file(p: &Path) -> io::Result<()> { - let canonicalized = match std_fs::canonicalize(p) { + let canonicalized = match try_canonicalize(p) { Ok(canonicalized) => canonicalized, Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), Err(err) => return Err(err), diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 7d9bae735e5..d240d8e491f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -30,16 +30,22 @@ use super::*; use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::{Const, ImplSubject}; +use std::cell::Cell; + +/// Whether we should define opaque types or just treat them opaquely. +/// +/// Currently only used to prevent predicate matching from matching anything +/// against opaque types. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum DefineOpaqueTypes { + Yes, + No, +} + pub struct At<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, pub cause: &'a ObligationCause<'tcx>, pub param_env: ty::ParamEnv<'tcx>, - /// Whether we should define opaque types - /// or just treat them opaquely. - /// Currently only used to prevent predicate - /// matching from matching anything against opaque - /// types. - pub define_opaque_types: bool, } pub struct Trace<'a, 'tcx> { @@ -55,7 +61,7 @@ impl<'tcx> InferCtxt<'tcx> { cause: &'a ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> At<'a, 'tcx> { - At { infcx: self, cause, param_env, define_opaque_types: false } + At { infcx: self, cause, param_env } } /// Forks the inference context, creating a new inference context with the same inference @@ -78,13 +84,13 @@ impl<'tcx> InferCtxt<'tcx> { in_snapshot: self.in_snapshot.clone(), universe: self.universe.clone(), intercrate: self.intercrate, + inside_canonicalization_ctxt: Cell::new(self.inside_canonicalization_ctxt()), } } } pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { fn to_trace( - tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -93,33 +99,21 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { } impl<'a, 'tcx> At<'a, 'tcx> { - pub fn define_opaque_types(self, define_opaque_types: bool) -> Self { - Self { define_opaque_types, ..self } - } - - /// Hacky routine for equating two impl headers in coherence. - pub fn eq_impl_headers( - self, - expected: &ty::ImplHeader<'tcx>, - actual: &ty::ImplHeader<'tcx>, - ) -> InferResult<'tcx, ()> { - debug!("eq_impl_header({:?} = {:?})", expected, actual); - match (expected.trait_ref, actual.trait_ref) { - (Some(a_ref), Some(b_ref)) => self.eq(a_ref, b_ref), - (None, None) => self.eq(expected.self_ty, actual.self_ty), - _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), - } - } - /// Makes `a <: b`, where `a` may or may not be expected. /// /// See [`At::trace_exp`] and [`Trace::sub`] for a version of /// this method that only requires `T: Relate<'tcx>` - pub fn sub_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()> + pub fn sub_exp<T>( + self, + define_opaque_types: DefineOpaqueTypes, + a_is_expected: bool, + a: T, + b: T, + ) -> InferResult<'tcx, ()> where T: ToTrace<'tcx>, { - self.trace_exp(a_is_expected, a, b).sub(a, b) + self.trace_exp(a_is_expected, a, b).sub(define_opaque_types, a, b) } /// Makes `actual <: expected`. For example, if type-checking a @@ -129,54 +123,81 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// /// See [`At::trace`] and [`Trace::sub`] for a version of /// this method that only requires `T: Relate<'tcx>` - pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> + pub fn sup<T>( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> where T: ToTrace<'tcx>, { - self.sub_exp(false, actual, expected) + self.sub_exp(define_opaque_types, false, actual, expected) } /// Makes `expected <: actual`. /// /// See [`At::trace`] and [`Trace::sub`] for a version of /// this method that only requires `T: Relate<'tcx>` - pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> + pub fn sub<T>( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> where T: ToTrace<'tcx>, { - self.sub_exp(true, expected, actual) + self.sub_exp(define_opaque_types, true, expected, actual) } /// Makes `expected <: actual`. /// /// See [`At::trace_exp`] and [`Trace::eq`] for a version of /// this method that only requires `T: Relate<'tcx>` - pub fn eq_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()> + pub fn eq_exp<T>( + self, + define_opaque_types: DefineOpaqueTypes, + a_is_expected: bool, + a: T, + b: T, + ) -> InferResult<'tcx, ()> where T: ToTrace<'tcx>, { - self.trace_exp(a_is_expected, a, b).eq(a, b) + self.trace_exp(a_is_expected, a, b).eq(define_opaque_types, a, b) } /// Makes `expected <: actual`. /// /// See [`At::trace`] and [`Trace::eq`] for a version of /// this method that only requires `T: Relate<'tcx>` - pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> + pub fn eq<T>( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> where T: ToTrace<'tcx>, { - self.trace(expected, actual).eq(expected, actual) + self.trace(expected, actual).eq(define_opaque_types, expected, actual) } - pub fn relate<T>(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()> + pub fn relate<T>( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + variance: ty::Variance, + actual: T, + ) -> InferResult<'tcx, ()> where T: ToTrace<'tcx>, { match variance { - ty::Variance::Covariant => self.sub(expected, actual), - ty::Variance::Invariant => self.eq(expected, actual), - ty::Variance::Contravariant => self.sup(expected, actual), + ty::Variance::Covariant => self.sub(define_opaque_types, expected, actual), + ty::Variance::Invariant => self.eq(define_opaque_types, expected, actual), + ty::Variance::Contravariant => self.sup(define_opaque_types, expected, actual), // We could make this make sense but it's not readily // exposed and I don't feel like dealing with it. Note @@ -195,11 +216,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// /// See [`At::trace`] and [`Trace::lub`] for a version of /// this method that only requires `T: Relate<'tcx>` - pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> + pub fn lub<T>( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'tcx, T> where T: ToTrace<'tcx>, { - self.trace(expected, actual).lub(expected, actual) + self.trace(expected, actual).lub(define_opaque_types, expected, actual) } /// Computes the greatest-lower-bound, or mutual subtype, of two @@ -208,11 +234,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// /// See [`At::trace`] and [`Trace::glb`] for a version of /// this method that only requires `T: Relate<'tcx>` - pub fn glb<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> + pub fn glb<T>( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'tcx, T> where T: ToTrace<'tcx>, { - self.trace(expected, actual).glb(expected, actual) + self.trace(expected, actual).glb(define_opaque_types, expected, actual) } /// Sets the "trace" values that will be used for @@ -233,7 +264,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b); + let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b); Trace { at: self, trace, a_is_expected } } } @@ -242,13 +273,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a <: b` where `a` may or may not be expected (if /// `a_is_expected` is true, then `a` is expected). #[instrument(skip(self), level = "debug")] - pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()> + pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); + let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields .sub(a_is_expected) .relate(a, b) @@ -259,13 +290,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a == b`; the expectation is set by the call to /// `trace()`. #[instrument(skip(self), level = "debug")] - pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()> + pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); + let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields .equate(a_is_expected) .relate(a, b) @@ -274,13 +305,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T> + pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); + let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields .lub(a_is_expected) .relate(a, b) @@ -289,13 +320,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T> + pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); + let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields .glb(a_is_expected) .relate(a, b) @@ -306,7 +337,6 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { fn to_trace( - tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -314,10 +344,10 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { ) -> TypeTrace<'tcx> { match (a, b) { (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => { - ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b) + ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b) } (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => { - ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b) + ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b) } (ImplSubject::Trait(_), ImplSubject::Inherent(_)) | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => { @@ -329,7 +359,6 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { fn to_trace( - _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -344,7 +373,6 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { fn to_trace( - _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -356,7 +384,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { impl<'tcx> ToTrace<'tcx> for Const<'tcx> { fn to_trace( - _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -371,7 +398,6 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { fn to_trace( - _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -399,7 +425,6 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { fn to_trace( - _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -411,7 +436,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { fn to_trace( - _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -426,7 +450,6 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { fn to_trace( - _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -441,24 +464,17 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { fn to_trace( - tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, b: Self, ) -> TypeTrace<'tcx> { - let a_ty = tcx.mk_projection(a.def_id, a.substs); - let b_ty = tcx.mk_projection(b.def_id, b.substs); - TypeTrace { - cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())), - } + TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) } } } impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { fn to_trace( - _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 8ac82653c0e..96a5f6532fe 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -561,6 +561,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { where V: TypeFoldable<TyCtxt<'tcx>>, { + let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt(); + let needs_canonical_flags = if canonicalize_region_mode.any() { TypeFlags::NEEDS_INFER | TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 90e89a18782..268896b671a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -14,7 +14,7 @@ use crate::infer::canonical::{ }; use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; use crate::traits::query::{Fallible, NoSolution}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt}; @@ -159,9 +159,7 @@ impl<'tcx> InferCtxt<'tcx> { .opaque_type_storage .opaque_types .iter() - .map(|&(k, ref v)| { - (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty) - }) + .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) .collect() } @@ -510,7 +508,7 @@ impl<'tcx> InferCtxt<'tcx> { let b = substitute_value(self.tcx, &result_subst, b); debug!(?a, ?b, "constrain opaque type"); obligations - .extend(self.at(cause, param_env).define_opaque_types(true).eq(a, b)?.obligations); + .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations); } Ok(InferOk { value: result_subst, obligations }) @@ -603,8 +601,11 @@ impl<'tcx> InferCtxt<'tcx> { match (value1.unpack(), value2.unpack()) { (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { - obligations - .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); + obligations.extend( + self.at(cause, param_env) + .eq(DefineOpaqueTypes::Yes, v1, v2)? + .into_obligations(), + ); } (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2)) if re1.is_erased() && re2.is_erased() => @@ -612,11 +613,14 @@ impl<'tcx> InferCtxt<'tcx> { // no action needed } (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { - obligations - .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); + obligations.extend( + self.at(cause, param_env) + .eq(DefineOpaqueTypes::Yes, v1, v2)? + .into_obligations(), + ); } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { - let ok = self.at(cause, param_env).eq(v1, v2)?; + let ok = self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, v1, v2)?; obligations.extend(ok.into_obligations()); } _ => { @@ -636,9 +640,11 @@ pub fn make_query_region_constraints<'tcx>( outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>, region_constraints: &RegionConstraintData<'tcx>, ) -> QueryRegionConstraints<'tcx> { - let RegionConstraintData { constraints, verifys, member_constraints } = region_constraints; + let RegionConstraintData { constraints, verifys, givens, member_constraints } = + region_constraints; assert!(verifys.is_empty()); + assert!(givens.is_empty()); debug!(?constraints); diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index a2332797e86..88a28e26005 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -27,7 +27,7 @@ use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; use super::type_variable::TypeVariableValue; -use super::{InferCtxt, MiscVariable, TypeTrace}; +use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_data_structures::sso::SsoHashMap; use rustc_hir::def_id::DefId; @@ -52,12 +52,7 @@ pub struct CombineFields<'infcx, 'tcx> { pub cause: Option<ty::relate::Cause>, pub param_env: ty::ParamEnv<'tcx>, pub obligations: PredicateObligations<'tcx>, - /// Whether we should define opaque types - /// or just treat them opaquely. - /// Currently only used to prevent predicate - /// matching from matching anything against opaque - /// types. - pub define_opaque_types: bool, + pub define_opaque_types: DefineOpaqueTypes, } #[derive(Copy, Clone, Debug)] @@ -133,7 +128,7 @@ impl<'tcx> InferCtxt<'tcx> { (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => { - relation.register_type_equate_obligation(a, b); + relation.register_type_relate_obligation(a, b); Ok(a) } @@ -194,10 +189,19 @@ impl<'tcx> InferCtxt<'tcx> { // the expected const's type. Specifically, we don't want const infer vars // to do any type shapeshifting before and after resolution. if let Err(guar) = compatible_types { - return Ok(self.tcx.const_error_with_guaranteed( - if relation.a_is_expected() { a.ty() } else { b.ty() }, - guar, - )); + // HACK: equating both sides with `[const error]` eagerly prevents us + // from leaving unconstrained inference vars during things like impl + // matching in the solver. + let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar); + if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() { + return self.unify_const_variable(vid, a_error); + } + let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar); + if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() { + return self.unify_const_variable(vid, b_error); + } + + return Ok(if relation.a_is_expected() { a_error } else { b_error }); } match (a.kind(), b.kind()) { @@ -838,23 +842,25 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() { - ty::PredicateKind::AliasEq(a.into(), b.into()) + ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate) } else { ty::PredicateKind::ConstEquate(a, b) })]); } - /// Register an obligation that both types must be equal to each other. - /// - /// If they aren't equal then the relation doesn't hold. - fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - - self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq( + /// Register an obligation that both types must be related to each other according to + /// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`] + fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate( a.into(), b.into(), + self.alias_relate_direction(), ))]); } + + /// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction + /// of the relation. + fn alias_relate_direction(&self) -> ty::AliasRelationDirection; } fn int_unification_error<'tcx>( diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 54a62326ef7..38002357cde 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -1,3 +1,4 @@ +use crate::infer::DefineOpaqueTypes; use crate::traits::PredicateObligations; use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir}; @@ -110,7 +111,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if self.fields.define_opaque_types && def_id.is_local() => + if self.fields.define_opaque_types == DefineOpaqueTypes::Yes + && def_id.is_local() => { self.fields.obligations.extend( infcx @@ -208,4 +210,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.fields.register_obligations(obligations); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + ty::AliasRelationDirection::Equate + } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 8a2b800af0e..fd16363a1db 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -359,10 +359,12 @@ impl<'tcx> InferCtxt<'tcx> { pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { let (def_id, substs) = match *ty.kind() { ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if matches!( - self.tcx.def_kind(def_id), - DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder - ) => + if matches!(self.tcx.def_kind(def_id), DefKind::OpaqueTy) => + { + (def_id, substs) + } + ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + if self.tcx.is_impl_trait_in_trait(def_id) => { (def_id, substs) } @@ -613,9 +615,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| { - // Only external crates, if either is from a local - // module we could have false positives - if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { + // Only report definitions from different crates. If both definitions + // are from a local module we could have false positives, e.g. + // let _ = [{struct Foo; Foo}, {struct Foo; Foo}]; + if did1.krate != did2.krate { let abs_path = |def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]); @@ -627,10 +630,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; if same_path().unwrap_or(false) { let crate_name = self.tcx.crate_name(did1.krate); - err.note(&format!( - "perhaps two different versions of crate `{}` are being used?", - crate_name - )); + let msg = if did1.is_local() || did2.is_local() { + format!( + "the crate `{crate_name}` is compiled multiple times, possibly with different configurations" + ) + } else { + format!( + "perhaps two different versions of crate `{crate_name}` are being used?" + ) + }; + err.note(msg); } } }; @@ -1568,6 +1577,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => { (false, Mismatch::Fixed("trait")) } + ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => { + (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id))) + } ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), }; let Some(vals) = self.values_str(values) else { @@ -1754,8 +1766,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) } (true, ty::Alias(ty::Projection, proj)) - if self.tcx.def_kind(proj.def_id) - == DefKind::ImplTraitPlaceholder => + if self.tcx.is_impl_trait_in_trait(proj.def_id) => { let sm = self.tcx.sess.source_map(); let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo()); @@ -2124,6 +2135,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match values { infer::Regions(exp_found) => self.expected_found_str(exp_found), infer::Terms(exp_found) => self.expected_found_str_term(exp_found), + infer::Aliases(exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 7ffe1fd20b4..e720af73c39 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -306,9 +306,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Replace the explicit self type with `Self` for better suggestion rendering .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper)) .substs; - let trait_item_substs = - ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id()) - .rebase_onto(self.tcx, impl_def_id, trait_substs); + let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id) + .rebase_onto(self.tcx, impl_def_id, trait_substs); let Ok(trait_predicates) = self .tcx diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index b33729d0be5..b38bbdfe7bb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -1,7 +1,7 @@ use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diagnostic, MultiSpan}; -use rustc_hir::{self as hir, def::DefKind}; +use rustc_hir as hir; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::Printer; @@ -75,7 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { diag.note("an associated type was expected, but a different one was found"); } (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p)) - if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder => + if !tcx.is_impl_trait_in_trait(proj.def_id) => { let p_def_id = tcx .generics_of(body_owner_def_id) @@ -222,7 +222,7 @@ impl<T> Trait<T> for X { diag.span_label(p_span, "this type parameter"); } } - (ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => { + (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { self.expected_projection( diag, proj_ty, @@ -231,7 +231,7 @@ impl<T> Trait<T> for X { cause.code(), ); } - (_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => { + (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { let msg = format!( "consider constraining the associated type `{}` to `{}`", values.found, values.expected, diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 55dcfd05e0a..ec122dc039f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -356,7 +356,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if !self.same_type_modulo_infer(*found_sig, *expected_sig) || !sig.is_suggestable(self.tcx, true) - || ty::util::is_intrinsic(self.tcx, *did) + || self.tcx.is_intrinsic(*did) { return; } @@ -400,8 +400,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if !self.same_type_modulo_infer(*found_sig, *expected_sig) || !found_sig.is_suggestable(self.tcx, true) || !expected_sig.is_suggestable(self.tcx, true) - || ty::util::is_intrinsic(self.tcx, *did1) - || ty::util::is_intrinsic(self.tcx, *did2) + || self.tcx.is_intrinsic(*did1) + || self.tcx.is_intrinsic(*did2) { return; } diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 49df393d83b..6395c4d4b20 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -2,8 +2,8 @@ use super::combine::{CombineFields, ObligationEmittingRelation}; use super::lattice::{self, LatticeDir}; -use super::InferCtxt; use super::Subtype; +use super::{DefineOpaqueTypes, InferCtxt}; use crate::traits::{ObligationCause, PredicateObligations}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; @@ -142,7 +142,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, Ok(()) } - fn define_opaque_types(&self) -> bool { + fn define_opaque_types(&self) -> DefineOpaqueTypes { self.fields.define_opaque_types } } @@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.fields.register_obligations(obligations); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + // FIXME(deferred_projection_equality): This isn't right, I think? + ty::AliasRelationDirection::Equate + } } diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index f377ac1d19e..7f4c141b97a 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -19,7 +19,7 @@ use super::combine::ObligationEmittingRelation; use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use super::InferCtxt; +use super::{DefineOpaqueTypes, InferCtxt}; use crate::traits::ObligationCause; use rustc_middle::ty::relate::RelateResult; @@ -36,7 +36,7 @@ pub trait LatticeDir<'f, 'tcx>: ObligationEmittingRelation<'tcx> { fn cause(&self) -> &ObligationCause<'tcx>; - fn define_opaque_types(&self) -> bool; + fn define_opaque_types(&self) -> DefineOpaqueTypes; // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. @@ -110,7 +110,7 @@ where ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b), (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if this.define_opaque_types() && def_id.is_local() => + if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() => { this.register_obligations( infcx diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index cf657756ff5..2c480355085 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -13,7 +13,7 @@ use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; use rustc_data_structures::intern::Interned; -use rustc_index::vec::IndexVec; +use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::PlaceholderRegion; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -132,6 +132,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } let graph = self.construct_graph(); + self.expand_givens(&graph); self.expansion(&mut var_data); self.collect_errors(&mut var_data, errors); self.collect_var_errors(&var_data, &graph, errors); @@ -163,6 +164,38 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } + fn expand_givens(&mut self, graph: &RegionGraph<'_>) { + // Givens are a kind of horrible hack to account for + // constraints like 'c <= '0 that are known to hold due to + // closure signatures (see the comment above on the `givens` + // field). They should go away. But until they do, the role + // of this fn is to account for the transitive nature: + // + // Given 'c <= '0 + // and '0 <= '1 + // then 'c <= '1 + + let seeds: Vec<_> = self.data.givens.iter().cloned().collect(); + for (r, vid) in seeds { + // While all things transitively reachable in the graph + // from the variable (`'0` in the example above). + let seed_index = NodeIndex(vid.index() as usize); + for succ_index in graph.depth_traverse(seed_index, OUTGOING) { + let succ_index = succ_index.0; + + // The first N nodes correspond to the region + // variables. Other nodes correspond to constant + // regions. + if succ_index < self.num_vars() { + let succ_vid = RegionVid::new(succ_index); + + // Add `'c <= '1`. + self.data.givens.insert((r, succ_vid)); + } + } + } + } + /// Gets the LUb of a given region and the empty region fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> { match *a_region { @@ -329,6 +362,18 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ) -> bool { debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data); + match *a_region { + // Check if this relationship is implied by a given. + ty::ReEarlyBound(_) | ty::ReFree(_) => { + if self.data.givens.contains(&(a_region, b_vid)) { + debug!("given"); + return false; + } + } + + _ => {} + } + match *b_data { VarValue::Empty(empty_ui) => { let lub = match self.lub_empty(a_region) { diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index c871ccb21f8..98cbd4c561c 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -2,8 +2,8 @@ use super::combine::{CombineFields, ObligationEmittingRelation}; use super::lattice::{self, LatticeDir}; -use super::InferCtxt; use super::Subtype; +use super::{DefineOpaqueTypes, InferCtxt}; use crate::traits::{ObligationCause, PredicateObligations}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; @@ -142,7 +142,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, Ok(()) } - fn define_opaque_types(&self) -> bool { + fn define_opaque_types(&self) -> DefineOpaqueTypes { self.fields.define_opaque_types } } @@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.fields.register_obligations(obligations) } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + // FIXME(deferred_projection_equality): This isn't right, I think? + ty::AliasRelationDirection::Equate + } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 66fb1db4618..9afe9cc1e76 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,3 +1,4 @@ +pub use self::at::DefineOpaqueTypes; pub use self::freshen::TypeFreshener; pub use self::lexical_region_resolve::RegionResolutionError; pub use self::LateBoundRegionConversionTime::*; @@ -38,6 +39,7 @@ use rustc_span::Span; use std::cell::{Cell, RefCell}; use std::fmt; +use std::ops::Drop; use self::combine::CombineFields; use self::error_reporting::TypeErrCtxt; @@ -187,6 +189,16 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] + fn try_type_variables_probe_ref( + &self, + vid: ty::TyVid, + ) -> Option<&type_variable::TypeVariableValue<'tcx>> { + // Uses a read-only view of the unification table, this way we don't + // need an undo log. + self.type_variable_storage.eq_relations_ref().try_probe_value(vid) + } + + #[inline] fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> { self.type_variable_storage.with_log(&mut self.undo_log) } @@ -331,6 +343,11 @@ pub struct InferCtxt<'tcx> { /// there is no type that the user could *actually name* that /// would satisfy it. This avoids crippling inference, basically. pub intercrate: bool, + + /// Flag that is set when we enter canonicalization. Used for debugging to ensure + /// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin` + /// inside non-canonicalization contexts. + inside_canonicalization_ctxt: Cell<bool>, } /// See the `error_reporting` module for more details. @@ -338,6 +355,7 @@ pub struct InferCtxt<'tcx> { pub enum ValuePairs<'tcx> { Regions(ExpectedFound<ty::Region<'tcx>>), Terms(ExpectedFound<ty::Term<'tcx>>), + Aliases(ExpectedFound<ty::AliasTy<'tcx>>), TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>), PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>), Sigs(ExpectedFound<ty::FnSig<'tcx>>), @@ -573,8 +591,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn intercrate(mut self) -> Self { - self.intercrate = true; + pub fn intercrate(mut self, intercrate: bool) -> Self { + self.intercrate = intercrate; self } @@ -621,6 +639,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, + inside_canonicalization_ctxt: Cell::new(false), } } } @@ -729,7 +748,7 @@ impl<'tcx> InferCtxt<'tcx> { &'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>, - define_opaque_types: bool, + define_opaque_types: DefineOpaqueTypes, ) -> CombineFields<'a, 'tcx> { CombineFields { infcx: self, @@ -855,12 +874,16 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot) } + pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { + self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup); + } + pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool where T: at::ToTrace<'tcx>, { let origin = &ObligationCause::dummy(); - self.probe(|_| self.at(origin, param_env).sub(a, b).is_ok()) + self.probe(|_| self.at(origin, param_env).sub(DefineOpaqueTypes::No, a, b).is_ok()) } pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool @@ -868,7 +891,7 @@ impl<'tcx> InferCtxt<'tcx> { T: at::ToTrace<'tcx>, { let origin = &ObligationCause::dummy(); - self.probe(|_| self.at(origin, param_env).eq(a, b).is_ok()) + self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok()) } #[instrument(skip(self), level = "debug")] @@ -963,7 +986,8 @@ impl<'tcx> InferCtxt<'tcx> { let ty::SubtypePredicate { a_is_expected, a, b } = self.instantiate_binder_with_placeholders(predicate); - let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; + let ok = + self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?; Ok(ok.unit()) })) @@ -1639,6 +1663,28 @@ impl<'tcx> InferCtxt<'tcx> { tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span) } + /// The returned function is used in a fast path. If it returns `true` the variable is + /// unchanged, `false` indicates that the status is unknown. + #[inline] + pub fn is_ty_infer_var_definitely_unchanged<'a>( + &'a self, + ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) { + // This hoists the borrow/release out of the loop body. + let inner = self.inner.try_borrow(); + + return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) { + (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => { + use self::type_variable::TypeVariableValue; + + match inner.try_type_variables_probe_ref(ty_var) { + Some(TypeVariableValue::Unknown { .. }) => true, + _ => false, + } + } + _ => false, + }; + } + /// `ty_or_const_infer_var_changed` is equivalent to one of these two: /// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`) /// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`) @@ -1689,6 +1735,31 @@ impl<'tcx> InferCtxt<'tcx> { } } } + + pub fn inside_canonicalization_ctxt(&self) -> bool { + self.inside_canonicalization_ctxt.get() + } + + pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> { + let prev_ctxt = self.inside_canonicalization_ctxt(); + self.inside_canonicalization_ctxt.set(true); + CanonicalizationCtxtGuard { prev_ctxt, infcx: self } + } + + fn set_canonicalization_ctxt_to(&self, ctxt: bool) { + self.inside_canonicalization_ctxt.set(ctxt); + } +} + +pub struct CanonicalizationCtxtGuard<'cx, 'tcx> { + prev_ctxt: bool, + infcx: &'cx InferCtxt<'tcx>, +} + +impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> { + fn drop(&mut self) { + self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt) + } } impl<'tcx> TypeErrCtxt<'_, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 573cd91a2a2..f5d20cb7ebf 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -28,6 +28,7 @@ use crate::traits::{Obligation, PredicateObligations}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; @@ -55,21 +56,6 @@ where ambient_variance: ty::Variance, ambient_variance_info: ty::VarianceDiagInfo<'tcx>, - - /// When we pass through a set of binders (e.g., when looking into - /// a `fn` type), we push a new bound region scope onto here. This - /// will contain the instantiated region for each region in those - /// binders. When we then encounter a `ReLateBound(d, br)`, we can - /// use the De Bruijn index `d` to find the right scope, and then - /// bound region name `br` to find the specific instantiation from - /// within that scope. See `replace_bound_region`. - /// - /// This field stores the instantiations for late-bound regions in - /// the `a` type. - a_scopes: Vec<BoundRegionScope<'tcx>>, - - /// Same as `a_scopes`, but for the `b` type. - b_scopes: Vec<BoundRegionScope<'tcx>>, } pub trait TypeRelatingDelegate<'tcx> { @@ -147,8 +133,6 @@ where delegate, ambient_variance, ambient_variance_info: ty::VarianceDiagInfo::default(), - a_scopes: vec![], - b_scopes: vec![], } } @@ -166,88 +150,6 @@ where } } - fn create_scope( - &mut self, - value: ty::Binder<'tcx, impl Relate<'tcx>>, - universally_quantified: UniversallyQuantified, - ) -> BoundRegionScope<'tcx> { - let mut scope = BoundRegionScope::default(); - - // Create a callback that creates (via the delegate) either an - // existential or placeholder region as needed. - let mut next_region = { - let delegate = &mut self.delegate; - let mut lazy_universe = None; - move |br: ty::BoundRegion| { - if universally_quantified.0 { - // The first time this closure is called, create a - // new universe for the placeholders we will make - // from here out. - let universe = lazy_universe.unwrap_or_else(|| { - let universe = delegate.create_next_universe(); - lazy_universe = Some(universe); - universe - }); - - let placeholder = ty::PlaceholderRegion { universe, name: br.kind }; - delegate.next_placeholder_region(placeholder) - } else { - delegate.next_existential_region_var(true, br.kind.get_name()) - } - } - }; - - value.skip_binder().visit_with(&mut ScopeInstantiator { - next_region: &mut next_region, - target_index: ty::INNERMOST, - bound_region_scope: &mut scope, - }); - - scope - } - - /// When we encounter binders during the type traversal, we record - /// the value to substitute for each of the things contained in - /// that binder. (This will be either a universal placeholder or - /// an existential inference variable.) Given the De Bruijn index - /// `debruijn` (and name `br`) of some binder we have now - /// encountered, this routine finds the value that we instantiated - /// the region with; to do so, it indexes backwards into the list - /// of ambient scopes `scopes`. - fn lookup_bound_region( - debruijn: ty::DebruijnIndex, - br: &ty::BoundRegion, - first_free_index: ty::DebruijnIndex, - scopes: &[BoundRegionScope<'tcx>], - ) -> ty::Region<'tcx> { - // The debruijn index is a "reverse index" into the - // scopes listing. So when we have INNERMOST (0), we - // want the *last* scope pushed, and so forth. - let debruijn_index = debruijn.index() - first_free_index.index(); - let scope = &scopes[scopes.len() - debruijn_index - 1]; - - // Find this bound region in that scope to map to a - // particular region. - scope.map[br] - } - - /// If `r` is a bound region, find the scope in which it is bound - /// (from `scopes`) and return the value that we instantiated it - /// with. Otherwise just return `r`. - fn replace_bound_region( - &self, - r: ty::Region<'tcx>, - first_free_index: ty::DebruijnIndex, - scopes: &[BoundRegionScope<'tcx>], - ) -> ty::Region<'tcx> { - debug!("replace_bound_regions(scopes={:?})", scopes); - if let ty::ReLateBound(debruijn, br) = *r { - Self::lookup_bound_region(debruijn, &br, first_free_index, scopes) - } else { - r - } - } - /// Push a new outlives requirement into our output set of /// constraints. fn push_outlives( @@ -314,18 +216,9 @@ where self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty); - // The generalized values we extract from `canonical_var_values` have - // 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)); - // Relate the generalized kind to the original one. let result = pair.relate_generalized_ty(self, generalized_ty); - // Restore the old scopes now. - *pair.vid_scopes(self) = old_a_scopes; - debug!("relate_ty_var: complete, result = {:?}", result); result } @@ -379,6 +272,97 @@ where trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); Ok(a) } + + #[instrument(skip(self), level = "debug")] + fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T + where + T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy, + { + if let Some(inner) = binder.no_bound_vars() { + return inner; + } + + let mut next_region = { + let nll_delegate = &mut self.delegate; + let mut lazy_universe = None; + + move |br: ty::BoundRegion| { + // The first time this closure is called, create a + // new universe for the placeholders we will make + // from here out. + let universe = lazy_universe.unwrap_or_else(|| { + let universe = nll_delegate.create_next_universe(); + lazy_universe = Some(universe); + universe + }); + + let placeholder = ty::PlaceholderRegion { universe, name: br.kind }; + debug!(?placeholder); + let placeholder_reg = nll_delegate.next_placeholder_region(placeholder); + debug!(?placeholder_reg); + + placeholder_reg + } + }; + + let delegate = FnMutDelegate { + regions: &mut next_region, + types: &mut |_bound_ty: ty::BoundTy| { + unreachable!("we only replace regions in nll_relate, not types") + }, + consts: &mut |_bound_var: ty::BoundVar, _ty| { + unreachable!("we only replace regions in nll_relate, not consts") + }, + }; + + let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate); + debug!(?replaced); + + replaced + } + + #[instrument(skip(self), level = "debug")] + fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T + where + T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy, + { + if let Some(inner) = binder.no_bound_vars() { + return inner; + } + + let mut next_region = { + let nll_delegate = &mut self.delegate; + let mut reg_map = FxHashMap::default(); + + move |br: ty::BoundRegion| { + if let Some(ex_reg_var) = reg_map.get(&br) { + return *ex_reg_var; + } else { + let ex_reg_var = + nll_delegate.next_existential_region_var(true, br.kind.get_name()); + debug!(?ex_reg_var); + reg_map.insert(br, ex_reg_var); + + ex_reg_var + } + } + }; + + let delegate = FnMutDelegate { + regions: &mut next_region, + types: &mut |_bound_ty: ty::BoundTy| { + unreachable!("we only replace regions in nll_relate, not types") + }, + consts: &mut |_bound_var: ty::BoundVar, _ty| { + unreachable!("we only replace regions in nll_relate, not consts") + }, + }; + + let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate); + debug!(?replaced); + + replaced + } } /// When we instantiate an inference variable with a value in @@ -396,14 +380,6 @@ trait VidValuePair<'tcx>: Debug { /// opposite part of the tuple from the vid). fn value_ty(&self) -> Ty<'tcx>; - /// Extract the scopes that apply to whichever side of the tuple - /// the vid was found on. See the comment where this is called - /// for more details on why we want them. - fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>>; - /// Given a generalized type G that should replace the vid, relate /// G to the value, putting G on whichever side the vid would have /// appeared. @@ -425,16 +401,6 @@ impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) { self.1 } - fn vid_scopes<'r, D>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - &mut relate.a_scopes - } - fn relate_generalized_ty<D>( &self, relate: &mut TypeRelating<'_, 'tcx, D>, @@ -457,16 +423,6 @@ impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) { self.0 } - fn vid_scopes<'r, D>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - &mut relate.b_scopes - } - fn relate_generalized_ty<D>( &self, relate: &mut TypeRelating<'_, 'tcx, D>, @@ -602,20 +558,14 @@ where ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!(?self.ambient_variance); - let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes); - let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes); - - debug!(?v_a); - debug!(?v_b); - if self.ambient_covariance() { // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`. - self.push_outlives(v_a, v_b, self.ambient_variance_info); + self.push_outlives(a, b, self.ambient_variance_info); } if self.ambient_contravariance() { // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`. - self.push_outlives(v_b, v_a, self.ambient_variance_info); + self.push_outlives(b, a, self.ambient_variance_info); } Ok(a) @@ -689,15 +639,6 @@ where // instantiation of B (i.e., B instantiated with // universals). - let b_scope = self.create_scope(b, UniversallyQuantified(true)); - let a_scope = self.create_scope(a, UniversallyQuantified(false)); - - debug!(?a_scope, "(existential)"); - debug!(?b_scope, "(universal)"); - - self.b_scopes.push(b_scope); - self.a_scopes.push(a_scope); - // Reset the ambient variance to covariant. This is needed // to correctly handle cases like // @@ -718,12 +659,14 @@ where // subtyping (i.e., `&'b u32 <: &{P} u32`). let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); - self.relate(a.skip_binder(), b.skip_binder())?; + // Note: the order here is important. Create the placeholders first, otherwise + // we assign the wrong universe to the existential! + let b_replaced = self.instantiate_binder_with_placeholders(b); + let a_replaced = self.instantiate_binder_with_existentials(a); - self.ambient_variance = variance; + self.relate(a_replaced, b_replaced)?; - self.b_scopes.pop().unwrap(); - self.a_scopes.pop().unwrap(); + self.ambient_variance = variance; } if self.ambient_contravariance() { @@ -733,26 +676,17 @@ where // instantiation of B (i.e., B instantiated with // existentials). Opposite of above. - let a_scope = self.create_scope(a, UniversallyQuantified(true)); - let b_scope = self.create_scope(b, UniversallyQuantified(false)); - - debug!(?a_scope, "(universal)"); - debug!(?b_scope, "(existential)"); - - self.a_scopes.push(a_scope); - self.b_scopes.push(b_scope); - // 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); - self.relate(a.skip_binder(), b.skip_binder())?; + let a_replaced = self.instantiate_binder_with_placeholders(a); + let b_replaced = self.instantiate_binder_with_existentials(b); - self.ambient_variance = variance; + self.relate(a_replaced, b_replaced)?; - self.b_scopes.pop().unwrap(); - self.a_scopes.pop().unwrap(); + self.ambient_variance = variance; } Ok(a) @@ -777,6 +711,34 @@ where fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.delegate.register_obligations(obligations); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance") + } + + fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + self.register_predicates([ty::Binder::dummy(match self.ambient_variance { + ty::Variance::Covariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Subtype, + ), + // a :> b is b <: a + ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( + b.into(), + a.into(), + ty::AliasRelationDirection::Subtype, + ), + ty::Variance::Invariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ), + // FIXME(deferred_projection_equality): Implement this when we trigger it. + // Probably just need to do nothing here. + ty::Variance::Bivariant => unreachable!(), + })]); + } } /// When we encounter a binder like `for<..> fn(..)`, we actually have diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index d5c824d4c41..3a0a0494a7e 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,11 +1,12 @@ +use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use super::{DefineOpaqueTypes, InferResult}; use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; -use hir::def::DefKind; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -16,18 +17,13 @@ use rustc_middle::ty::{ TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_span::Span; - use std::ops::ControlFlow; -pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; - mod table; +pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; -use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use super::InferResult; - /// Information about the opaque types whose values we /// are inferring in this function (these are the `impl Trait` that /// appear in the return type). @@ -481,9 +477,7 @@ where } } - ty::Alias(ty::Projection, proj) - if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder => - { + ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => { // Skip lifetime parameters that are not captures. let variances = self.tcx.variances_of(proj.def_id); @@ -547,8 +541,7 @@ impl<'tcx> InferCtxt<'tcx> { if let Some(prev) = prev { obligations = self .at(&cause, param_env) - .define_opaque_types(true) - .eq_exp(a_is_expected, prev, hidden_ty)? + .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? .obligations; } @@ -563,8 +556,7 @@ impl<'tcx> InferCtxt<'tcx> { // FIXME(RPITIT): Don't replace RPITITs with inference vars. ty::Alias(ty::Projection, projection_ty) if !projection_ty.has_escaping_bound_vars() - && tcx.def_kind(projection_ty.def_id) - != DefKind::ImplTraitPlaceholder => + && !tcx.is_impl_trait_in_trait(projection_ty.def_id) => { self.infer_projection( param_env, diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index a480ee5429e..24e3c34dd94 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,9 +1,9 @@ use crate::infer::free_regions::FreeRegionMap; -use crate::infer::GenericKind; +use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::OutlivesBound; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; -use rustc_middle::ty::{self, Region}; +use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region}; use super::explicit_outlives_bounds; @@ -75,7 +75,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { region_bound_pairs: Default::default(), }; - builder.add_outlives_bounds(explicit_outlives_bounds(param_env)); + builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env)); builder } @@ -89,10 +89,11 @@ impl<'tcx> OutlivesEnvironment<'tcx> { /// Create a new `OutlivesEnvironment` with extra outlives bounds. pub fn with_bounds( param_env: ty::ParamEnv<'tcx>, + infcx: Option<&InferCtxt<'tcx>>, extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>, ) -> Self { let mut builder = Self::builder(param_env); - builder.add_outlives_bounds(extra_bounds); + builder.add_outlives_bounds(infcx, extra_bounds); builder.build() } @@ -119,7 +120,12 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { } /// Processes outlives bounds that are known to hold, whether from implied or other sources. - fn add_outlives_bounds<I>(&mut self, outlives_bounds: I) + /// + /// The `infcx` parameter is optional; if the implied bounds may + /// contain inference variables, it must be supplied, in which + /// case we will register "givens" on the inference context. (See + /// `RegionConstraintData`.) + fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I) where I: IntoIterator<Item = OutlivesBound<'tcx>>, { @@ -136,14 +142,27 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { self.region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } - OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) { - ( - ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_), - ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_), - ) => self.region_relation.add(r_a, r_b), - (ty::ReError(_), _) | (_, ty::ReError(_)) => {} - _ => bug!("add_outlives_bounds: unexpected regions"), - }, + OutlivesBound::RegionSubRegion(r_a, r_b) => { + if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { + infcx + .expect("no infcx provided but region vars found") + .add_given(r_a, vid_b); + } else { + // In principle, we could record (and take + // advantage of) every relationship here, but + // we are also free not to -- it simply means + // strictly less that we can successfully type + // check. Right now we only look for things + // relationships between free regions. (It may + // also be that we should revise our inference + // system to be more general and to make use + // of *every* relationship that arises here, + // but presently we do not.) + if r_a.is_free_or_static() && r_b.is_free() { + self.region_relation.add(r_a, r_b) + } + } + } } } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 83f3d5a74fb..048dad3a48b 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -22,7 +22,7 @@ pub fn explicit_outlives_bounds<'tcx>( ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::WellFormed(..) diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index f795047709e..fa6529dfa93 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> { // completely change the normalization routine with the new solver. // // The new solver correctly handles projection equality so this hack - // is not necessary. if re-enabled it should emit `PredicateKind::AliasEq` + // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate` // not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver // `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`. return projection_ty.to_ty(self.tcx); diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 89ada23c667..e413b2bb570 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -424,6 +424,9 @@ impl<'tcx> MiniGraph<'tcx> { &AddConstraint(Constraint::RegSubReg(a, b)) => { each_edge(a, b); } + &AddGiven(a, b) => { + each_edge(a, tcx.mk_re_var(b)); + } &AddVerify(i) => span_bug!( verifys[i].origin.span(), "we never add verifications while doing higher-ranked things", diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 7b272dfd2a4..0b86d9c1fb8 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -7,7 +7,7 @@ use super::{ InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; @@ -104,6 +104,26 @@ pub struct RegionConstraintData<'tcx> { /// An example is a `A <= B` where neither `A` nor `B` are /// inference variables. pub verifys: Vec<Verify<'tcx>>, + + /// A "given" is a relationship that is known to hold. In + /// particular, we often know from closure fn signatures that a + /// particular free region must be a subregion of a region + /// variable: + /// + /// foo.iter().filter(<'a> |x: &'a &'b T| ...) + /// + /// In situations like this, `'b` is in fact a region variable + /// introduced by the call to `iter()`, and `'a` is a bound region + /// on the closure (as indicated by the `<'a>` prefix). If we are + /// naive, we wind up inferring that `'b` must be `'static`, + /// because we require that it be greater than `'a` and we do not + /// know what `'a` is precisely. + /// + /// This hashmap is used to avoid that naive scenario. Basically + /// we record the fact that `'a <= 'b` is implied by the fn + /// signature, and then ignore the constraint when solving + /// equations. This is a bit of a hack but seems to work. + pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>, } /// Represents a constraint that influences the inference process. @@ -277,6 +297,9 @@ pub(crate) enum UndoLog<'tcx> { /// We added the given `verify`. AddVerify(usize), + /// We added the given `given`. + AddGiven(Region<'tcx>, ty::RegionVid), + /// We added a GLB/LUB "combination variable". AddCombination(CombineMapType, TwoRegions<'tcx>), } @@ -325,6 +348,9 @@ impl<'tcx> RegionConstraintStorage<'tcx> { self.data.verifys.pop(); assert_eq!(self.data.verifys.len(), index); } + AddGiven(sub, sup) => { + self.data.givens.remove(&(sub, sup)); + } AddCombination(Glb, ref regions) => { self.glbs.remove(regions); } @@ -466,6 +492,15 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { self.undo_log.push(AddVerify(index)); } + pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) { + // cannot add givens once regions are resolved + if self.data.givens.insert((sub, sup)) { + debug!("add_given({:?} <= {:?})", sub, sup); + + self.undo_log.push(AddGiven(sub, sup)); + } + } + pub(super) fn make_eqregion( &mut self, origin: SubregionOrigin<'tcx>, @@ -769,8 +804,11 @@ impl<'tcx> RegionConstraintData<'tcx> { /// Returns `true` if this region constraint data contains no constraints, and `false` /// otherwise. pub fn is_empty(&self) -> bool { - let RegionConstraintData { constraints, member_constraints, verifys } = self; - constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty() + let RegionConstraintData { constraints, member_constraints, verifys, givens } = self; + constraints.is_empty() + && member_constraints.is_empty() + && verifys.is_empty() + && givens.is_empty() } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 3e8c2052de8..fc73ca7606d 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -1,5 +1,5 @@ use super::combine::{CombineFields, RelationDir}; -use super::{ObligationEmittingRelation, SubregionOrigin}; +use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; @@ -138,7 +138,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if self.fields.define_opaque_types && def_id.is_local() => + if self.fields.define_opaque_types == DefineOpaqueTypes::Yes + && def_id.is_local() => { self.fields.obligations.extend( infcx @@ -235,4 +236,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.fields.register_obligations(obligations); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + ty::AliasRelationDirection::Subtype + } } diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 263c6a47dd2..f7ab05b2d49 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -190,6 +190,11 @@ impl<'tcx> TypeVariableStorage<'tcx> { ) -> TypeVariableTable<'a, 'tcx> { TypeVariableTable { storage: self, undo_log } } + + #[inline] + pub(crate) fn eq_relations_ref(&self) -> &ut::UnificationTableStorage<TyVidEqKey<'tcx>> { + &self.eq_relations + } } impl<'tcx> TypeVariableTable<'_, 'tcx> { diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 77c67c14ecc..dd9b2e548c7 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -8,6 +8,8 @@ mod project; mod structural_impls; pub mod util; +use std::cmp; + use hir::def_id::LocalDefId; use rustc_hir as hir; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -139,6 +141,14 @@ impl<'tcx, O> Obligation<'tcx, O> { Self::with_depth(tcx, cause, 0, param_env, predicate) } + /// We often create nested obligations without setting the correct depth. + /// + /// To deal with this evaluate and fulfill explicitly update the depth + /// of nested obligations using this function. + pub fn set_depth_from_parent(&mut self, parent_depth: usize) { + self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth); + } + pub fn with_depth( tcx: TyCtxt<'tcx>, cause: ObligationCause<'tcx>, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index c07ff516579..0d2faeba5fc 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -293,7 +293,7 @@ impl<'tcx> Elaborator<'tcx> { // Nothing to elaborate } ty::PredicateKind::Ambiguous => {} - ty::PredicateKind::AliasEq(..) => { + ty::PredicateKind::AliasRelate(..) => { // No } ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index ac6e8fca695..96d6a1cb062 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_borrowck = { path = "../rustc_borrowck" } rustc_builtin_macros = { path = "../rustc_builtin_macros" } rustc_expand = { path = "../rustc_expand" } +rustc_fs_util = { path = "../rustc_fs_util" } rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 71bdd4df95b..413b40ab808 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -3,7 +3,6 @@ use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; -use ast::CRATE_NODE_ID; use rustc_ast::{self as ast, visit}; use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; @@ -12,6 +11,7 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::PResult; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; +use rustc_fs_util::try_canonicalize; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; @@ -76,22 +76,14 @@ pub fn register_plugins<'a>( sess: &'a Session, metadata_loader: &'a dyn MetadataLoader, register_lints: impl Fn(&Session, &mut LintStore), - mut krate: ast::Crate, + pre_configured_attrs: &[ast::Attribute], crate_name: Symbol, -) -> Result<(ast::Crate, LintStore)> { - krate = sess.time("attributes_injection", || { - rustc_builtin_macros::cmdline_attrs::inject( - krate, - &sess.parse_sess, - &sess.opts.unstable_opts.crate_attr, - ) - }); - - let (krate, features) = rustc_expand::config::features(sess, krate, CRATE_NODE_ID); +) -> Result<LintStore> { // these need to be set "early" so that expansion sees `quote` if enabled. + let features = rustc_expand::config::features(sess, pre_configured_attrs); sess.init_features(features); - let crate_types = util::collect_crate_types(sess, &krate.attrs); + let crate_types = util::collect_crate_types(sess, pre_configured_attrs); sess.init_crate_types(crate_types); let stable_crate_id = StableCrateId::new( @@ -117,8 +109,9 @@ pub fn register_plugins<'a>( let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints()); register_lints(sess, &mut lint_store); - let registrars = - sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate)); + let registrars = sess.time("plugin_loading", || { + plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs) + }); sess.time("plugin_registration", || { let mut registry = plugin::Registry { lint_store: &mut lint_store }; for registrar in registrars { @@ -126,7 +119,7 @@ pub fn register_plugins<'a>( } }); - Ok((krate, lint_store)) + Ok(lint_store) } fn pre_expansion_lint<'a>( @@ -173,19 +166,29 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> { /// harness if one is to be provided, injection of a dependency on the /// standard library and prelude, and name resolution. #[instrument(level = "trace", skip(krate, resolver))] -fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) -> ast::Crate { +fn configure_and_expand( + mut krate: ast::Crate, + pre_configured_attrs: &[ast::Attribute], + resolver: &mut Resolver<'_, '_>, +) -> ast::Crate { let tcx = resolver.tcx(); let sess = tcx.sess; let lint_store = unerased_lint_store(tcx); let crate_name = tcx.crate_name(LOCAL_CRATE); - pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name); + let lint_check_node = (&krate, pre_configured_attrs); + pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), lint_check_node, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); - krate = sess.time("crate_injection", || { - rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess) + let num_standard_library_imports = sess.time("crate_injection", || { + rustc_builtin_macros::standard_library_imports::inject( + &mut krate, + pre_configured_attrs, + resolver, + sess, + ) }); - util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer()); + util::check_attr_crate_type(sess, pre_configured_attrs, &mut resolver.lint_buffer()); // Expand all macros krate = sess.time("macro_expand_crate", || { @@ -222,7 +225,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) // Create the config for macro expansion let features = sess.features_untracked(); - let recursion_limit = get_recursion_limit(&krate.attrs, sess); + let recursion_limit = get_recursion_limit(pre_configured_attrs, sess); let cfg = rustc_expand::expand::ExpansionConfig { features: Some(features), recursion_limit, @@ -235,6 +238,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) let lint_store = LintStoreExpandImpl(lint_store); let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store)); + ecx.num_standard_library_imports = num_standard_library_imports; // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); @@ -263,7 +267,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) }); sess.time("maybe_building_test_harness", || { - rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate) + rustc_builtin_macros::test_harness::inject(&mut krate, sess, resolver) }); let has_proc_macro_decls = sess.time("AST_validation", || { @@ -287,12 +291,12 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) sess.emit_warning(errors::ProcMacroCratePanicAbort); } - krate = sess.time("maybe_create_a_macro_crate", || { + sess.time("maybe_create_a_macro_crate", || { let is_test_crate = sess.opts.test; rustc_builtin_macros::proc_macro_harness::inject( + &mut krate, sess, resolver, - krate, is_proc_macro_crate, has_proc_macro_decls, is_test_crate, @@ -356,7 +360,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { tcx.registered_tools(()), Some(lint_buffer), rustc_lint::BuiltinCombinedEarlyLintPass::new(), - &**krate, + (&**krate, &*krate.attrs), ) } @@ -405,12 +409,12 @@ where } fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool { - let input_path = input_path.canonicalize().ok(); + let input_path = try_canonicalize(input_path).ok(); if input_path.is_none() { return false; } let check = |output_path: &PathBuf| { - if output_path.canonicalize().ok() == input_path { Some(()) } else { None } + if try_canonicalize(output_path).ok() == input_path { Some(()) } else { None } }; check_output(output_paths, check).is_some() } @@ -557,9 +561,9 @@ fn resolver_for_lowering<'tcx>( ) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> { let arenas = Resolver::arenas(); let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`. - let krate = tcx.crate_for_resolver(()).steal(); - let mut resolver = Resolver::new(tcx, &krate, &arenas); - let krate = configure_and_expand(krate, &mut resolver); + let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal(); + let mut resolver = Resolver::new(tcx, &pre_configured_attrs, krate.spans.inner_span, &arenas); + let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver); // Make sure we don't mutate the cstore from here on. tcx.untracked().cstore.leak(); diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 9bf7778bfb2..1c58caa0353 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -1,3 +1,4 @@ +use rustc_ast::attr; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -8,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> { for id in tcx.hir().items() { let attrs = tcx.hir().attrs(id.hir_id()); - if tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) { + if attr::contains_name(attrs, sym::rustc_proc_macro_decls) { decls = Some(id.owner_id.def_id); } } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 58ad044b399..d2293780836 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -88,8 +88,9 @@ pub struct Queries<'tcx> { dep_graph_future: Query<Option<DepGraphFuture>>, parse: Query<ast::Crate>, + pre_configure: Query<(ast::Crate, ast::AttrVec)>, crate_name: Query<Symbol>, - register_plugins: Query<(ast::Crate, Lrc<LintStore>)>, + register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>, dep_graph: Query<DepGraph>, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, @@ -106,6 +107,7 @@ impl<'tcx> Queries<'tcx> { hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), dep_graph_future: Default::default(), parse: Default::default(), + pre_configure: Default::default(), crate_name: Default::default(), register_plugins: Default::default(), dep_graph: Default::default(), @@ -133,17 +135,36 @@ impl<'tcx> Queries<'tcx> { .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())) } - pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> { + pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> { + self.pre_configure.compute(|| { + let mut krate = self.parse()?.steal(); + + let sess = self.session(); + rustc_builtin_macros::cmdline_attrs::inject( + &mut krate, + &sess.parse_sess, + &sess.opts.unstable_opts.crate_attr, + ); + + let pre_configured_attrs = + rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); + Ok((krate, pre_configured_attrs)) + }) + } + + pub fn register_plugins( + &self, + ) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> { self.register_plugins.compute(|| { let crate_name = *self.crate_name()?.borrow(); - let krate = self.parse()?.steal(); + let (krate, pre_configured_attrs) = self.pre_configure()?.steal(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; - let (krate, lint_store) = passes::register_plugins( + let lint_store = passes::register_plugins( self.session(), &*self.codegen_backend().metadata_loader(), self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), - krate, + &pre_configured_attrs, crate_name, )?; @@ -154,17 +175,17 @@ impl<'tcx> Queries<'tcx> { // called, which happens within passes::register_plugins(). self.dep_graph_future().ok(); - Ok((krate, Lrc::new(lint_store))) + Ok((krate, pre_configured_attrs, Lrc::new(lint_store))) }) } fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> { self.crate_name.compute(|| { Ok({ - let parse_result = self.parse()?; - let krate = parse_result.borrow(); + let pre_configure_result = self.pre_configure()?; + let (_, pre_configured_attrs) = &*pre_configure_result.borrow(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. - find_crate_name(self.session(), &krate.attrs) + find_crate_name(self.session(), pre_configured_attrs) }) }) } @@ -188,7 +209,7 @@ impl<'tcx> Queries<'tcx> { pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> { self.gcx.compute(|| { let crate_name = *self.crate_name()?.borrow(); - let (krate, lint_store) = self.register_plugins()?.steal(); + let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal(); let sess = self.session(); @@ -215,7 +236,7 @@ impl<'tcx> Queries<'tcx> { feed.crate_name(crate_name); let feed = tcx.feed_unit_query(); - feed.crate_for_resolver(tcx.arena.alloc(Steal::new(krate))); + feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); feed.metadata_loader( tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())), ); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 18d84a7023a..eb5990507fb 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -2,6 +2,7 @@ use crate::interface::parse_cfgspecs; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::rustc_optgroups; use rustc_session::config::Input; @@ -699,6 +700,7 @@ fn test_unstable_options_tracking_hash() { untracked!(threads, 99); untracked!(time_llvm_passes, true); untracked!(time_passes, true); + untracked!(time_passes_format, TimePassesFormat::Json); untracked!(trace_macros, true); untracked!(track_diagnostics, true); untracked!(trim_diagnostic_paths, false); @@ -744,6 +746,7 @@ fn test_unstable_options_tracking_hash() { tracked!(emit_thin_lto, false); tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); + tracked!(flatten_format_args, true); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); tracked!(function_sections, Some(false)); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 043892410ce..8abdcebb751 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -505,7 +505,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu .opts .crate_name .clone() - .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string())) + .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string())) .unwrap_or_else(|| sess.io.input.filestem().to_owned()); OutputFilenames::new( diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5b2100b5da9..64c3ef45137 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -358,29 +358,29 @@ impl EarlyLintPass for UnsafeCode { } ast::ItemKind::Fn(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn); } } ast::ItemKind::Static(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic); } } @@ -391,10 +391,10 @@ impl EarlyLintPass for UnsafeCode { fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { if let ast::AssocItemKind::Fn(..) = it.kind { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod); } } @@ -1123,12 +1123,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn(.., ref generics, _) => { - if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) { + if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) { check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span); } } hir::ItemKind::Const(..) => { - if cx.sess().contains_name(attrs, sym::no_mangle) { + if attr::contains_name(attrs, sym::no_mangle) { // account for "pub const" (#45562) let start = cx .tcx @@ -1152,9 +1152,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { - if let Some(no_mangle_attr) = cx - .sess() - .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) + if let Some(no_mangle_attr) = + attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) { check_no_mangle_on_generic_fn( no_mangle_attr, @@ -1306,7 +1305,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { if fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller // Now, check if the function has the `#[track_caller]` attribute - && let Some(attr) = cx.tcx.get_attr(def_id.to_def_id(), sym::track_caller) + && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) { cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { label: span, @@ -1601,7 +1600,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { // Ignore projections, as they can only be global // if the trait bound is global Clause(Clause::Projection(..)) | - AliasEq(..) | + AliasRelate(..) | // Ignore bounds that a user can't type WellFormed(..) | ObjectSafe(..) | @@ -1836,7 +1835,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { } let attrs = cx.tcx.hir().attrs(it.hir_id()); - if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) { + if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) { cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems); } } @@ -2748,10 +2747,7 @@ impl ClashingExternDeclarations { // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a // bottleneck, this does just fine. - ( - overridden_link_name, - tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span, - ) + (overridden_link_name, tcx.get_attr(fi.owner_id, sym::link_name).unwrap().span) }) { SymbolName::Link(overridden_link_name, overridden_link_name_span) @@ -2781,8 +2777,7 @@ impl ClashingExternDeclarations { // Given a transparent newtype, reach through and grab the inner // type unless the newtype makes the type non-null. - let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> { - let mut ty = ty; + let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> { loop { if let ty::Adt(def, substs) = *ty.kind() { let is_transparent = def.repr().transparent(); @@ -2792,14 +2787,14 @@ impl ClashingExternDeclarations { ty, is_transparent, is_non_null ); if is_transparent && !is_non_null { - debug_assert!(def.variants().len() == 1); + debug_assert_eq!(def.variants().len(), 1); let v = &def.variant(VariantIdx::new(0)); - ty = transparent_newtype_field(tcx, v) - .expect( - "single-variant transparent structure with zero-sized field", - ) - .ty(tcx, substs); - continue; + // continue with `ty`'s non-ZST field, + // otherwise `ty` is a ZST and we can return + if let Some(field) = transparent_newtype_field(tcx, v) { + ty = field.ty(tcx, substs); + continue; + } } } debug!("non_transparent_ty -> {:?}", ty); @@ -2813,10 +2808,8 @@ impl ClashingExternDeclarations { if !seen_types.insert((a, b)) { // We've encountered a cycle. There's no point going any further -- the types are // structurally the same. - return true; - } - let tcx = cx.tcx; - if a == b { + true + } else if a == b { // All nominally-same types are structurally same, too. true } else { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index f5a711315ea..626c09fea07 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -910,6 +910,10 @@ pub trait LintContext: Sized { Applicability::MachineApplicable, ); } + BuiltinLintDiagnostics::AmbiguousGlobReexports { name, namespace, first_reexport_span, duplicate_reexport_span } => { + db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace)); + db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace)); + } } // Rewrap `db`, and pass control to the user. decorate(db) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 337a19dd024..9b0d8d6c072 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -341,7 +341,7 @@ pub trait EarlyCheckNode<'a>: Copy { 'a: 'b; } -impl<'a> EarlyCheckNode<'a> for &'a ast::Crate { +impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) { fn id(self) -> ast::NodeId { ast::CRATE_NODE_ID } @@ -349,15 +349,15 @@ impl<'a> EarlyCheckNode<'a> for &'a ast::Crate { where 'a: 'b, { - &self.attrs + &self.1 } fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>) where 'a: 'b, { - lint_callback!(cx, check_crate, self); - ast_visit::walk_crate(cx, self); - lint_callback!(cx, check_crate_post, self); + lint_callback!(cx, check_crate, self.0); + ast_visit::walk_crate(cx, self.0); + lint_callback!(cx, check_crate_post, self.0); } } diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index a3367ae4a9f..7b58bf03bbe 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -11,6 +11,7 @@ use rustc_hir as hir; use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause}; use rustc_middle::ty::{self, List}; use rustc_span::{sym, Span}; +use rustc_trait_selection::traits::ObligationCtxt; declare_lint! { /// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values. @@ -136,20 +137,22 @@ fn suggest_question_mark<'tcx>( let ty = substs.type_at(0); let infcx = cx.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); let cause = ObligationCause::new( span, body_def_id, rustc_infer::traits::ObligationCauseCode::MiscObligation, ); - let errors = rustc_trait_selection::traits::fully_solve_bound( - &infcx, + + ocx.register_bound( cause, - ty::ParamEnv::empty(), + cx.param_env, // Erase any region vids from the type, which may not be resolved infcx.tcx.erase_regions(ty), into_iterator_did, ); - errors.is_empty() + ocx.select_all_or_error().is_empty() } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index a14dc20fca3..9c7feadaf87 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -386,7 +386,7 @@ impl LateLintPass<'_> for Diagnostics { for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) { if let Some(owner_did) = hir_id.as_owner() { found_parent_with_attr = found_parent_with_attr - || cx.tcx.has_attr(owner_did.to_def_id(), sym::rustc_lint_diagnostics); + || cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics); } debug!(?parent); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 20ab0af5856..308c02929ca 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1390,7 +1390,7 @@ pub struct UnusedOp<'a> { pub op: &'a str, #[label] pub label: Span, - #[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")] + #[suggestion(style = "verbose", code = "let _ = ", applicability = "maybe-incorrect")] pub suggestion: Span, } @@ -1434,17 +1434,15 @@ pub struct UnusedDef<'a, 'b> { } #[derive(Subdiagnostic)] -pub enum UnusedDefSuggestion { - #[suggestion( - lint_suggestion, - style = "verbose", - code = "let _ = ", - applicability = "machine-applicable" - )] - Default { - #[primary_span] - span: Span, - }, +#[suggestion( + lint_suggestion, + style = "verbose", + code = "let _ = ", + applicability = "maybe-incorrect" +)] +pub struct UnusedDefSuggestion { + #[primary_span] + pub span: Span, } // Needed because of def_path_str diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 71e2e66bdeb..9efc14849c7 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -328,8 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - cx.sess() - .find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) + attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { @@ -384,9 +383,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { match &fk { FnKind::Method(ident, sig, ..) => match method_context(cx, id) { MethodLateContext::PlainImpl => { - if sig.header.abi != Abi::Rust - && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) - { + if sig.header.abi != Abi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { return; } self.check_snake_case(cx, "method", ident); @@ -398,7 +395,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { }, FnKind::ItemFn(ident, _, header) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != Abi::Rust && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) { + if header.abi != Abi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { return; } self.check_snake_case(cx, "function", ident); @@ -491,7 +488,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(it.hir_id()); match it.kind { - hir::ItemKind::Static(..) if !cx.sess().contains_name(attrs, sym::no_mangle) => { + hir::ItemKind::Static(..) if !attr::contains_name(attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident); } hir::ItemKind::Const(..) => { diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 883a56cb3ce..f9d43fe2200 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -27,6 +27,8 @@ declare_lint! { /// ### Example /// /// ```rust + /// #![feature(type_alias_impl_trait)] + /// /// trait Duh {} /// /// impl Duh for i32 {} @@ -41,7 +43,9 @@ declare_lint! { /// type Assoc = F; /// } /// - /// fn test() -> impl Trait<Assoc = impl Sized> { + /// type Tait = impl Sized; + /// + /// fn test() -> impl Trait<Assoc = Tait> { /// 42 /// } /// ``` @@ -54,7 +58,7 @@ declare_lint! { /// /// Although the hidden type, `i32` does satisfy this bound, we do not /// consider the return type to be well-formed with this lint. It can be - /// fixed by changing `impl Sized` into `impl Sized + Send`. + /// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Send`. pub OPAQUE_HIDDEN_INFERRED_BOUND, Warn, "detects the use of nested `impl Trait` types in associated type bounds that are not general enough" @@ -64,7 +68,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; }; + let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { return; }; let def_id = item.owner_id.def_id.to_def_id(); let infcx = &cx.tcx.infer_ctxt().build(); // For every projection predicate in the opaque type's explicit bounds, @@ -81,6 +85,17 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // have opaques in them anyways. let Some(proj_term) = proj.term.ty() else { continue }; + // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"... + if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind() + && cx.tcx.parent(opaque_ty.def_id) == def_id + && matches!( + opaque.origin, + hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) + ) + { + continue; + } + let proj_ty = cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs); // For every instance of the projection type in the bounds, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 2fab82d55cd..faca61fc29b 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span); let type_lint_emitted_or_suppressed = match must_use_result { Some(path) => { - emit_must_use_untranslated(cx, &path, "", "", 1); + emit_must_use_untranslated(cx, &path, "", "", 1, false); true } None => false, @@ -358,6 +358,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_pre_path, descr_post_path, 1, + false, ) }) .is_some() @@ -370,6 +371,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_pre: &str, descr_post: &str, plural_len: usize, + is_inner: bool, ) { let plural_suffix = pluralize!(plural_len); @@ -377,20 +379,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { MustUsePath::Suppressed => {} MustUsePath::Boxed(path) => { let descr_pre = &format!("{}boxed ", descr_pre); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); } MustUsePath::Opaque(path) => { let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); } MustUsePath::TraitObject(path) => { let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); } MustUsePath::TupleElement(elems) => { for (index, path) in elems { let descr_post = &format!(" in tuple element {}", index); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + emit_must_use_untranslated( + cx, path, descr_pre, descr_post, plural_len, true, + ); } } MustUsePath::Array(path, len) => { @@ -401,6 +405,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_pre, descr_post, plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)), + true, ); } MustUsePath::Closure(span) => { @@ -418,19 +423,6 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Def(span, def_id, reason) => { - let suggestion = if matches!( - cx.tcx.get_diagnostic_name(*def_id), - Some(sym::add) - | Some(sym::sub) - | Some(sym::mul) - | Some(sym::div) - | Some(sym::rem) - | Some(sym::neg), - ) { - Some(UnusedDefSuggestion::Default { span: span.shrink_to_lo() }) - } else { - None - }; cx.emit_spanned_lint( UNUSED_MUST_USE, *span, @@ -440,7 +432,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx, def_id: *def_id, note: *reason, - suggestion, + suggestion: (!is_inner) + .then_some(UnusedDefSuggestion { span: span.shrink_to_lo() }), }, ); } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 91966e75b5f..9d6ab0b75df 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3230,6 +3230,45 @@ declare_lint! { }; } +declare_lint! { + /// The `ambiguous_glob_reexports` lint detects cases where names re-exported via globs + /// collide. Downstream users trying to use the same name re-exported from multiple globs + /// will receive a warning pointing out redefinition of the same name. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(ambiguous_glob_reexports)] + /// pub mod foo { + /// pub type X = u8; + /// } + /// + /// pub mod bar { + /// pub type Y = u8; + /// pub type X = u8; + /// } + /// + /// pub use foo::*; + /// pub use bar::*; + /// + /// + /// pub fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This was previously accepted but it could silently break a crate's downstream users code. + /// For example, if `foo::*` and `bar::*` were re-exported before `bar::X` was added to the + /// re-exports, down stream users could use `this_crate::X` without problems. However, adding + /// `bar::X` would cause compilation errors in downstream crates because `X` is defined + /// multiple times in the same namespace of `this_crate`. + pub AMBIGUOUS_GLOB_REEXPORTS, + Warn, + "ambiguous glob re-exports", +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3337,6 +3376,7 @@ declare_lint_pass! { NAMED_ARGUMENTS_USED_POSITIONALLY, IMPLIED_BOUNDS_ENTAILMENT, BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + AMBIGUOUS_GLOB_REEXPORTS, ] } @@ -3968,14 +4008,9 @@ declare_lint! { /// /// ### Example /// - /// ```rust,ignore (need FFI) - /// #![feature(ffi_unwind_calls)] + /// ```rust /// #![feature(c_unwind)] - /// - /// # mod impl { - /// # #[no_mangle] - /// # pub fn "C-unwind" fn foo() {} - /// # } + /// #![warn(ffi_unwind_calls)] /// /// extern "C-unwind" { /// fn foo(); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6f22bdabff4..69a8b691ab2 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -529,6 +529,16 @@ pub enum BuiltinLintDiagnostics { vis_span: Span, ident_span: Span, }, + AmbiguousGlobReexports { + /// The name for which collision(s) have occurred. + name: String, + /// The name space for whihc the collision(s) occurred in. + namespace: String, + /// Span where the name is first re-exported. + first_reexport_span: Span, + /// Span where the same name is also re-exported. + duplicate_reexport_span: Span, + }, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 9fe59a1d826..f8e9ec535e4 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -333,6 +333,7 @@ fn main() { } else if target.contains("darwin") || target.contains("freebsd") || target.contains("windows-gnullvm") + || target.contains("aix") { "c++" } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() { diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index bee5c8541d6..4d7c133e09b 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_fs_util = { path = "../rustc_fs_util" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f870a1db82d..23c1aebb8ae 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -6,11 +6,11 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::{self as ast, *}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard}; use rustc_expand::base::SyntaxExtension; -use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_index::vec::IndexVec; use rustc_middle::ty::TyCtxt; @@ -46,9 +46,8 @@ pub struct CStore { /// This crate has a `#[alloc_error_handler]` item. has_alloc_error_handler: bool, - /// This map is used to verify we get no hash conflicts between - /// `StableCrateId` values. - pub(crate) stable_crate_ids: FxHashMap<StableCrateId, CrateNum>, + /// The interned [StableCrateId]s. + pub(crate) stable_crate_ids: StableCrateIdMap, /// Unused externs of the crate unused_externs: Vec<Symbol>, @@ -144,9 +143,21 @@ impl CStore { }) } - fn alloc_new_crate_num(&mut self) -> CrateNum { - self.metas.push(None); - CrateNum::new(self.metas.len() - 1) + fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result<CrateNum, CrateError> { + assert_eq!(self.metas.len(), self.stable_crate_ids.len()); + let num = CrateNum::new(self.stable_crate_ids.len()); + if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) { + let crate_name0 = root.name(); + if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) { + Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)) + } else { + Err(CrateError::SymbolConflictsCurrent(crate_name0)) + } + } else { + self.metas.push(None); + self.stable_crate_ids.insert(root.stable_crate_id(), num); + Ok(num) + } } pub fn has_crate_data(&self, cnum: CrateNum) -> bool { @@ -247,7 +258,7 @@ impl CStore { } pub fn new(sess: &Session) -> CStore { - let mut stable_crate_ids = FxHashMap::default(); + let mut stable_crate_ids = StableCrateIdMap::default(); stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE); CStore { // We add an empty entry for LOCAL_CRATE (which maps to zero) in @@ -342,42 +353,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None } - fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError> { - // Check for (potential) conflicts with the local crate - if self.sess.local_stable_crate_id() == root.stable_crate_id() { - return Err(CrateError::SymbolConflictsCurrent(root.name())); - } - - // Check for conflicts with any crate loaded so far - for (_, other) in self.cstore.iter_crate_data() { - // Same stable crate id but different SVH - if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() { - bug!( - "Previously returned E0523 here. \ - See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\ - root.name() = {}.", - root.name() - ); - } - } - - Ok(()) - } - - fn verify_no_stable_crate_id_hash_conflicts( - &mut self, - root: &CrateRoot, - cnum: CrateNum, - ) -> Result<(), CrateError> { - if let Some(existing) = self.cstore.stable_crate_ids.insert(root.stable_crate_id(), cnum) { - let crate_name0 = root.name(); - let crate_name1 = self.cstore.get_crate_data(existing).name(); - return Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)); - } - - Ok(()) - } - fn register_crate( &mut self, host_lib: Option<Library>, @@ -396,7 +371,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep); // Claim this crate number and cache it - let cnum = self.cstore.alloc_new_crate_num(); + let cnum = self.cstore.intern_stable_crate_id(&crate_root)?; info!( "register crate `{}` (cnum = {}. private_dep = {})", @@ -432,14 +407,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None }; - // Perform some verification *after* resolve_crate_deps() above is - // known to have been successful. It seems that - in error cases - the - // cstore can be in a temporarily invalid state between cnum allocation - // and dependency resolution and the verification code would produce - // ICEs in that case (see #83045). - self.verify_no_symbol_conflicts(&crate_root)?; - self.verify_no_stable_crate_id_hash_conflicts(&crate_root, cnum)?; - let crate_metadata = CrateMetadata::new( self.sess, &self.cstore, @@ -720,8 +687,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // compilation mode also comes into play. let desired_strategy = self.sess.panic_strategy(); let mut runtime_found = false; - let mut needs_panic_runtime = - self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime); + let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime); for (cnum, data) in self.cstore.iter_crate_data() { needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime(); @@ -789,7 +755,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { info!("loading profiler"); let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime); - if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) { + if name == sym::profiler_builtins && attr::contains_name(&krate.attrs, sym::no_core) { self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore); } @@ -803,14 +769,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } fn inject_allocator_crate(&mut self, krate: &ast::Crate) { - self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) { + self.cstore.has_global_allocator = match &*global_allocator_spans(krate) { [span1, span2, ..] => { self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 }); true } spans => !spans.is_empty(), }; - self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) { + self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) { [span1, span2, ..] => { self.sess .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); @@ -822,7 +788,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically // written down in liballoc. - if !self.sess.contains_name(&krate.attrs, sym::needs_allocator) + if !attr::contains_name(&krate.attrs, sym::needs_allocator) && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator()) { return; @@ -881,7 +847,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // allocator. At this point our allocator request is typically fulfilled // by the standard library, denoted by the `#![default_lib_allocator]` // attribute. - if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) + if !attr::contains_name(&krate.attrs, sym::default_lib_allocator) && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) { self.sess.emit_err(errors::GlobalAllocRequired); @@ -1003,7 +969,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } None => item.ident.name, }; - let dep_kind = if self.sess.contains_name(&item.attrs, sym::no_link) { + let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) { CrateDepKind::MacrosOnly } else { CrateDepKind::Explicit @@ -1049,16 +1015,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } -fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { - struct Finder<'a> { - sess: &'a Session, +fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> { + struct Finder { name: Symbol, spans: Vec<Span>, } - impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> { + impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, item: &'ast ast::Item) { if item.ident.name == self.name - && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol) + && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { self.spans.push(item.span); } @@ -1067,21 +1032,20 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { } let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc)); - let mut f = Finder { sess, name, spans: Vec::new() }; + let mut f = Finder { name, spans: Vec::new() }; visit::walk_crate(&mut f, krate); f.spans } -fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { - struct Finder<'a> { - sess: &'a Session, +fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> { + struct Finder { name: Symbol, spans: Vec<Span>, } - impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> { + impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, item: &'ast ast::Item) { if item.ident.name == self.name - && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol) + && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { self.spans.push(item.span); } @@ -1090,7 +1054,7 @@ fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { } let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom)); - let mut f = Finder { sess, name, spans: Vec::new() }; + let mut f = Finder { name, spans: Vec::new() }; visit::walk_crate(&mut f, krate); f.spans } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index c48e681eb94..79c42a128e7 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -222,6 +222,7 @@ use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; +use rustc_fs_util::try_canonicalize; use rustc_session::config::{self, CrateType}; use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::FileSearch; @@ -236,7 +237,7 @@ use snap::read::FrameDecoder; use std::borrow::Cow; use std::io::{Read, Result as IoResult, Write}; use std::path::{Path, PathBuf}; -use std::{cmp, fmt, fs}; +use std::{cmp, fmt}; #[derive(Clone)] pub(crate) struct CrateLocator<'a> { @@ -441,7 +442,7 @@ impl<'a> CrateLocator<'a> { info!("lib candidate: {}", spf.path.display()); let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default(); - let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone()); + let path = try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone()); if seen_paths.contains(&path) { continue; }; @@ -636,7 +637,7 @@ impl<'a> CrateLocator<'a> { // as well. if let Some((prev, _)) = &ret { let sysroot = self.sysroot; - let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf()); + let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf()); if prev.starts_with(&sysroot) { continue; } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index d6f68b2e140..b855c8e4332 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -46,7 +46,7 @@ pub fn find_native_static_library( } fn find_bundled_library( - name: Option<Symbol>, + name: Symbol, verbatim: Option<bool>, kind: NativeLibKind, has_cfg: bool, @@ -58,7 +58,7 @@ fn find_bundled_library( { let verbatim = verbatim.unwrap_or(false); let search_paths = &sess.target_filesearch(PathKind::Native).search_path_dirs(); - return find_native_static_library(name.unwrap().as_str(), verbatim, search_paths, sess) + return find_native_static_library(name.as_str(), verbatim, search_paths, sess) .file_name() .and_then(|s| s.to_str()) .map(Symbol::intern); @@ -336,10 +336,16 @@ impl<'tcx> Collector<'tcx> { if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() { sess.emit_err(errors::IncompatibleWasmLink { span }); } - } else if name.is_none() { - sess.emit_err(errors::LinkRequiresName { span: m.span }); } + if wasm_import_module.is_some() { + (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule)); + } + let Some((name, name_span)) = name else { + sess.emit_err(errors::LinkRequiresName { span: m.span }); + continue; + }; + // Do this outside of the loop so that `import_name_type` can be specified before `kind`. if let Some((_, span)) = import_name_type { if kind != Some(NativeLibKind::RawDylib) { @@ -349,8 +355,8 @@ impl<'tcx> Collector<'tcx> { let dll_imports = match kind { Some(NativeLibKind::RawDylib) => { - if let Some((name, span)) = name && name.as_str().contains('\0') { - sess.emit_err(errors::RawDylibNoNul { span }); + if name.as_str().contains('\0') { + sess.emit_err(errors::RawDylibNoNul { span: name_span }); } foreign_mod_items .iter() @@ -389,7 +395,6 @@ impl<'tcx> Collector<'tcx> { } }; - let name = name.map(|(name, _)| name); let kind = kind.unwrap_or(NativeLibKind::Unspecified); let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), sess); self.libs.push(NativeLib { @@ -398,7 +403,6 @@ impl<'tcx> Collector<'tcx> { kind, cfg, foreign_module: Some(it.owner_id.to_def_id()), - wasm_import_module: wasm_import_module.map(|(name, _)| name), verbatim, dll_imports, }); @@ -415,11 +419,7 @@ impl<'tcx> Collector<'tcx> { self.tcx.sess.emit_err(errors::LibFrameworkApple); } if let Some(ref new_name) = lib.new_name { - let any_duplicate = self - .libs - .iter() - .filter_map(|lib| lib.name.as_ref()) - .any(|n| n.as_str() == lib.name); + let any_duplicate = self.libs.iter().any(|n| n.name.as_str() == lib.name); if new_name.is_empty() { self.tcx.sess.emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name }); } else if !any_duplicate { @@ -444,33 +444,28 @@ impl<'tcx> Collector<'tcx> { let mut existing = self .libs .drain_filter(|lib| { - if let Some(lib_name) = lib.name { - if lib_name.as_str() == passed_lib.name { - // FIXME: This whole logic is questionable, whether modifiers are - // involved or not, library reordering and kind overriding without - // explicit `:rename` in particular. - if lib.has_modifiers() || passed_lib.has_modifiers() { - match lib.foreign_module { - Some(def_id) => { - self.tcx.sess.emit_err(errors::NoLinkModOverride { - span: Some(self.tcx.def_span(def_id)), - }) - } - None => self - .tcx - .sess - .emit_err(errors::NoLinkModOverride { span: None }), - }; - } - if passed_lib.kind != NativeLibKind::Unspecified { - lib.kind = passed_lib.kind; - } - if let Some(new_name) = &passed_lib.new_name { - lib.name = Some(Symbol::intern(new_name)); - } - lib.verbatim = passed_lib.verbatim; - return true; + if lib.name.as_str() == passed_lib.name { + // FIXME: This whole logic is questionable, whether modifiers are + // involved or not, library reordering and kind overriding without + // explicit `:rename` in particular. + if lib.has_modifiers() || passed_lib.has_modifiers() { + match lib.foreign_module { + Some(def_id) => self.tcx.sess.emit_err(errors::NoLinkModOverride { + span: Some(self.tcx.def_span(def_id)), + }), + None => { + self.tcx.sess.emit_err(errors::NoLinkModOverride { span: None }) + } + }; + } + if passed_lib.kind != NativeLibKind::Unspecified { + lib.kind = passed_lib.kind; + } + if let Some(new_name) = &passed_lib.new_name { + lib.name = Symbol::intern(new_name); } + lib.verbatim = passed_lib.verbatim; + return true; } false }) @@ -478,7 +473,7 @@ impl<'tcx> Collector<'tcx> { if existing.is_empty() { // Add if not found let new_name: Option<&str> = passed_lib.new_name.as_deref(); - let name = Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))); + let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name)); let sess = self.tcx.sess; let filename = find_bundled_library(name, passed_lib.verbatim, passed_lib.kind, false, sess); @@ -488,7 +483,6 @@ impl<'tcx> Collector<'tcx> { kind: passed_lib.kind, cfg: None, foreign_module: None, - wasm_import_module: None, verbatim: passed_lib.verbatim, dll_imports: Vec::new(), }); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 0070e46ffdf..06a64f0db0e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -925,10 +925,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { tcx.mk_adt_def(did, adt_kind, variants, repr) } - fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics { - self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess)) - } - fn get_visibility(self, id: DefIndex) -> Visibility<DefId> { self.root .tables @@ -1045,13 +1041,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.tables.optimized_mir.get(self, id).is_some() } - fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId { - match self.def_kind(id) { - DefKind::Mod | DefKind::Enum | DefKind::Trait => self.get_expn_that_defined(id, sess), - _ => panic!("Expected module, found {:?}", self.local_def_id(id)), - } - } - fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool { self.root .tables @@ -1709,10 +1698,6 @@ impl CrateMetadata { self.root.name } - pub(crate) fn stable_crate_id(&self) -> StableCrateId { - self.root.stable_crate_id - } - pub(crate) fn hash(&self) -> Svh { self.root.hash } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index a9843395336..3a50d7c9363 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -13,6 +13,7 @@ use rustc_middle::arena::ArenaAllocatable; use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, TyCtxt}; @@ -226,15 +227,7 @@ provide! { tcx, def_id, other, cdata, lookup_default_body_stability => { table } lookup_deprecation_entry => { table } params_in_repr => { table } - // FIXME: Could be defaulted, but `LazyValue<UnusedGenericParams>` is not `FixedSizeEncoding`.. - unused_generic_params => { - cdata - .root - .tables - .unused_generic_params - .get(cdata, def_id.index) - .map_or_else(|| ty::UnusedGenericParams::new_all_used(), |lazy| lazy.decode((cdata, tcx))) - } + unused_generic_params => { cdata.root.tables.unused_generic_params.get(cdata, def_id.index) } opt_def_kind => { table_direct } impl_parent => { table } impl_polarity => { table_direct } @@ -262,7 +255,7 @@ provide! { tcx, def_id, other, cdata, .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } - associated_items_for_impl_trait_in_trait => { table_defaulted_array } + associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array } visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } @@ -375,10 +368,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { *providers = Providers { allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(), alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(), - is_private_dep: |_tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - false - }, + is_private_dep: |_tcx, LocalCrate| false, native_library: |tcx, id| { tcx.native_libraries(id.krate) .iter() @@ -394,12 +384,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .contains(&id) }) }, - native_libraries: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - native_libs::collect(tcx) - }, - foreign_modules: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); + native_libraries: |tcx, LocalCrate| native_libs::collect(tcx), + foreign_modules: |tcx, LocalCrate| { foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect() }, @@ -497,19 +483,16 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { }, dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)), - has_global_allocator: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - CStore::from_tcx(tcx).has_global_allocator() - }, - has_alloc_error_handler: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - CStore::from_tcx(tcx).has_alloc_error_handler() - }, + has_global_allocator: |tcx, LocalCrate| CStore::from_tcx(tcx).has_global_allocator(), + has_alloc_error_handler: |tcx, LocalCrate| CStore::from_tcx(tcx).has_alloc_error_handler(), postorder_cnums: |tcx, ()| { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) }, crates: |tcx, ()| { + // The list of loaded crates is now frozen in query cache, + // so make sure cstore is not mutably accessed from here on. + tcx.untracked().cstore.leak(); tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum)) }, ..*providers @@ -557,20 +540,16 @@ impl CStore { ) } - pub fn get_span_untracked(&self, def_id: DefId, sess: &Session) -> Span { + pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span { self.get_crate_data(def_id.krate).get_span(def_id.index, sess) } - pub fn def_kind(&self, def: DefId) -> DefKind { + pub fn def_kind_untracked(&self, def: DefId) -> DefKind { self.get_crate_data(def.krate).def_kind(def.index) } - pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize { - self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes - } - - pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { - self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess) + pub fn expn_that_defined_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { + self.get_crate_data(def_id.krate).get_expn_that_defined(def_id.index, sess) } /// Only public-facing way to traverse all the definitions in a non-local crate. @@ -580,14 +559,6 @@ impl CStore { self.get_crate_data(cnum).num_def_ids() } - pub fn item_attrs_untracked<'a>( - &'a self, - def_id: DefId, - sess: &'a Session, - ) -> impl Iterator<Item = ast::Attribute> + 'a { - self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess) - } - pub fn get_proc_macro_quoted_span_untracked( &self, cnum: CrateNum, @@ -615,7 +586,10 @@ impl CrateStore for CStore { } fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum { - self.stable_crate_ids[&stable_crate_id] + *self + .stable_crate_ids + .get(&stable_crate_id) + .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")) } /// Returns the `DefKey` for a given `DefId`. This indicates the diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9649ce2c5a7..2652a4280d3 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -24,9 +24,10 @@ use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, }; use rustc_middle::mir::interpret; +use rustc_middle::query::LocalCrate; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; -use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; +use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_middle::util::common::to_readable_str; @@ -609,10 +610,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { _ = stat!("mir", || self.encode_mir()); - _ = stat!("items", || { - self.encode_def_ids(); - self.encode_info_for_items(); - }); + _ = stat!("def-ids", || self.encode_def_ids()); + + _ = stat!("items", || self.encode_info_for_items()); let interpret_alloc_index = stat!("interpret-alloc-index", || { let mut interpret_alloc_index = Vec::new(); @@ -681,17 +681,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), - has_default_lib_allocator: tcx - .sess - .contains_name(&attrs, sym::default_lib_allocator), + has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator), proc_macro_data, debugger_visualizers, - compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins), - needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator), - needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime), - no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), - panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), - profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), + compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins), + needs_allocator: attr::contains_name(&attrs, sym::needs_allocator), + needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime), + no_builtins: attr::contains_name(&attrs, sym::no_builtins), + panic_runtime: attr::contains_name(&attrs, sym::panic_runtime), + profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime), symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(), crate_deps, @@ -1016,7 +1014,6 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::Const | DefKind::Static(..) | DefKind::TyAlias - | DefKind::OpaqueTy | DefKind::ForeignTy | DefKind::Impl { .. } | DefKind::AssocFn @@ -1027,8 +1024,20 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::AnonConst | DefKind::InlineConst => true, + DefKind::OpaqueTy => { + let opaque = tcx.hir().expect_item(def_id).expect_opaque_ty(); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) + && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() + { + false + } else { + true + } + } + DefKind::ImplTraitPlaceholder => { - let parent_def_id = tcx.impl_trait_in_trait_parent(def_id.to_def_id()); + let parent_def_id = tcx.impl_trait_in_trait_parent_fn(def_id.to_def_id()); let assoc_item = tcx.associated_item(parent_def_id); match assoc_item.container { // Always encode an RPIT in an impl fn, since it always has a body @@ -1044,7 +1053,13 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> let assoc_item = tcx.associated_item(def_id); match assoc_item.container { ty::AssocItemContainer::ImplContainer => true, - ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(), + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) always encode RPITITs, + // since we need to be able to "project" from an RPITIT associated item + // to an opaque when installing the default projection predicates in + // default trait methods with RPITITs. + ty::AssocItemContainer::TraitContainer => { + assoc_item.defaultness(tcx).has_value() || assoc_item.opt_rpitit_info.is_some() + } } } DefKind::TyParam => { @@ -1198,8 +1213,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } if should_encode_fn_impl_trait_in_trait(tcx, def_id) { - let table = tcx.associated_items_for_impl_trait_in_trait(def_id); - record_defaulted_array!(self.tables.associated_items_for_impl_trait_in_trait[def_id] <- table); + let table = tcx.associated_types_for_impl_traits_in_associated_fn(def_id); + record_defaulted_array!(self.tables.associated_types_for_impl_traits_in_associated_fn[def_id] <- table); } } @@ -1440,9 +1455,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())); let unused = tcx.unused_generic_params(instance); - if !unused.all_used() { - record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); - } + self.tables.unused_generic_params.set(def_id.local_def_index, unused); } // Encode all the deduced parameter attributes for everything that has MIR, even for items @@ -1732,11 +1745,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Proc-macros may have attributes like `#[allow_internal_unstable]`, // so downstream crates need access to them. let attrs = hir.attrs(proc_macro); - let macro_kind = if tcx.sess.contains_name(attrs, sym::proc_macro) { + let macro_kind = if attr::contains_name(attrs, sym::proc_macro) { MacroKind::Bang - } else if tcx.sess.contains_name(attrs, sym::proc_macro_attribute) { + } else if attr::contains_name(attrs, sym::proc_macro_attribute) { MacroKind::Attr - } else if let Some(attr) = tcx.sess.find_by_name(attrs, sym::proc_macro_derive) { + } else if let Some(attr) = attr::find_by_name(attrs, sym::proc_macro_derive) { // This unwrap chain should have been checked by the proc-macro harness. name = attr.meta_item_list().unwrap()[0] .meta_item() @@ -1868,7 +1881,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, ); fx_hash_map @@ -2234,18 +2246,16 @@ pub fn provide(providers: &mut Providers) { doc_link_resolutions: |tcx, def_id| { tcx.resolutions(()) .doc_link_resolutions - .get(&def_id.expect_local()) + .get(&def_id) .expect("no resolutions for a doc link") }, doc_link_traits_in_scope: |tcx, def_id| { tcx.resolutions(()) .doc_link_traits_in_scope - .get(&def_id.expect_local()) + .get(&def_id) .expect("no traits in scope for a doc link") }, - traits_in_crate: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - + traits_in_crate: |tcx, LocalCrate| { let mut traits = Vec::new(); for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { @@ -2257,9 +2267,7 @@ pub fn provide(providers: &mut Providers) { traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); tcx.arena.alloc_slice(&traits) }, - trait_impls_in_crate: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - + trait_impls_in_crate: |tcx, LocalCrate| { let mut trait_impls = Vec::new(); for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index e71a1c98102..6dc6041b284 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -354,8 +354,9 @@ define_tables! { explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>, inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, - associated_items_for_impl_trait_in_trait: Table<DefIndex, LazyArray<DefId>>, + associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>, opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>, + unused_generic_params: Table<DefIndex, UnusedGenericParams>, - optional: attributes: Table<DefIndex, LazyArray<ast::Attribute>>, @@ -398,7 +399,6 @@ define_tables! { trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>, trait_item_def_id: Table<DefIndex, RawDefId>, expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>, - unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>, params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>, repr_options: Table<DefIndex, LazyValue<ReprOptions>>, // `def_keys` and `def_path_hashes` represent a lazy version of a diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index b89d48ec15a..364fa74ab7b 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -3,7 +3,7 @@ use crate::rmeta::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def::{CtorKind, CtorOf}; use rustc_index::vec::Idx; -use rustc_middle::ty::ParameterizedOverTcx; +use rustc_middle::ty::{ParameterizedOverTcx, UnusedGenericParams}; use rustc_serialize::opaque::FileEncoder; use rustc_serialize::Encoder as _; use rustc_span::hygiene::MacroKind; @@ -50,6 +50,16 @@ impl IsDefault for DefPathHash { } } +impl IsDefault for UnusedGenericParams { + fn is_default(&self) -> bool { + // UnusedGenericParams encodes the *un*usedness as a bitset. + // This means that 0 corresponds to all bits used, which is indeed the default. + let is_default = self.bits() == 0; + debug_assert_eq!(is_default, self.all_used()); + is_default + } +} + /// Helper trait, for encoding to, and decoding from, a fixed number of bytes. /// Used mainly for Lazy positions and lengths. /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`, @@ -271,6 +281,21 @@ impl FixedSizeEncoding for bool { } } +impl FixedSizeEncoding for UnusedGenericParams { + type ByteArray = [u8; 4]; + + #[inline] + fn from_bytes(b: &[u8; 4]) -> Self { + let x: u32 = u32::from_bytes(b); + UnusedGenericParams::from_bits(x) + } + + #[inline] + fn write_to_bytes(self, b: &mut [u8; 4]) { + self.bits().write_to_bytes(b); + } +} + // NOTE(eddyb) there could be an impl for `usize`, which would enable a more // generic `LazyValue<T>` impl, but in the general case we might not need / want // to fit every `usize` in `u32`. diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 72907fba5e6..9f16ecbdaa9 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -36,7 +36,7 @@ macro_rules! arena_types { )>, [] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>, [] metadata_loader: rustc_data_structures::steal::Steal<Box<rustc_session::cstore::MetadataLoaderDyn>>, - [] crate_for_resolver: rustc_data_structures::steal::Steal<rustc_ast::ast::Crate>, + [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>, [] resolutions: rustc_middle::ty::ResolverGlobalCtxt, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8a4c10cd71c..89a485b47ca 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,4 +1,5 @@ use crate::hir::{ModuleItems, Owner}; +use crate::query::LocalCrate; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; @@ -6,7 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::*; @@ -187,7 +188,7 @@ impl<'hir> Map<'hir> { ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), ItemKind::Mod(..) => DefKind::Mod, ItemKind::OpaqueTy(ref opaque) => { - if opaque.in_trait { + if opaque.in_trait && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { DefKind::ImplTraitPlaceholder } else { DefKind::OpaqueTy @@ -1131,8 +1132,7 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { - debug_assert_eq!(crate_num, LOCAL_CRATE); +pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { let krate = tcx.hir_crate(()); let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash"); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 403b2b65088..0d8a8c9cdfd 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -147,18 +147,18 @@ pub fn provide(providers: &mut Providers) { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; providers.def_span = |tcx, def_id| { - let def_id = def_id.expect_local(); + let def_id = def_id; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP) }; providers.def_ident_span = |tcx, def_id| { - let def_id = def_id.expect_local(); + let def_id = def_id; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.hir().opt_ident_span(hir_id) }; providers.fn_arg_names = |tcx, id| { let hir = tcx.hir(); - let def_id = id.expect_local(); + let def_id = id; let hir_id = hir.local_def_id_to_hir_id(def_id); if let Some(body_id) = hir.maybe_body_owned_by(def_id) { tcx.arena.alloc_from_iter(hir.body_param_names(body_id)) @@ -176,12 +176,10 @@ pub fn provide(providers: &mut Providers) { span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id); } }; - providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local()); + providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id); providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; - providers.expn_that_defined = |tcx, id| { - let id = id.expect_local(); - tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()) - }; + providers.expn_that_defined = + |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()); providers.in_scope_traits_map = |tcx, id| { tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map) }; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index b34651c3ea7..9c575f6eb9f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -401,8 +401,6 @@ impl<'tcx> Body<'tcx> { LocalKind::ReturnPointer } else if index < self.arg_count + 1 { LocalKind::Arg - } else if self.local_decls[local].is_user_variable() { - LocalKind::Var } else { LocalKind::Temp } @@ -572,6 +570,13 @@ impl<T> ClearCrossCrate<T> { } } + pub fn as_mut(&mut self) -> ClearCrossCrate<&mut T> { + match self { + ClearCrossCrate::Clear => ClearCrossCrate::Clear, + ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v), + } + } + pub fn assert_crate_local(self) -> T { match self { ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), @@ -661,9 +666,7 @@ impl Atom for Local { /// Classifies locals into categories. See `Body::local_kind`. #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] pub enum LocalKind { - /// User-declared variable binding. - Var, - /// Compiler-introduced temporary. + /// User-declared variable binding or compiler-introduced temporary. Temp, /// Function argument. Arg, @@ -760,7 +763,7 @@ pub struct LocalDecl<'tcx> { pub mutability: Mutability, // FIXME(matthewjasper) Don't store in this in `Body` - pub local_info: Option<Box<LocalInfo<'tcx>>>, + pub local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>, /// `true` if this is an internal local. /// @@ -778,13 +781,6 @@ pub struct LocalDecl<'tcx> { /// generator. pub internal: bool, - /// If this local is a temporary and `is_block_tail` is `Some`, - /// then it is a temporary created for evaluation of some - /// subexpression of some block's tail expression (with no - /// intervening statement context). - // FIXME(matthewjasper) Don't store in this in `Body` - pub is_block_tail: Option<BlockTailInfo>, - /// The type of this local. pub ty: Ty<'tcx>, @@ -890,7 +886,7 @@ pub enum LocalInfo<'tcx> { /// The `BindingForm` is solely used for local diagnostics when generating /// warnings/errors when compiling the current crate, and therefore it need /// not be visible across crates. - User(ClearCrossCrate<BindingForm<'tcx>>), + User(BindingForm<'tcx>), /// A temporary created that references the static with the given `DefId`. StaticRef { def_id: DefId, is_thread_local: bool }, /// A temporary created that references the const with the given `DefId` @@ -898,13 +894,23 @@ pub enum LocalInfo<'tcx> { /// A temporary created during the creation of an aggregate /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`) AggregateTemp, + /// A temporary created for evaluation of some subexpression of some block's tail expression + /// (with no intervening statement context). + // FIXME(matthewjasper) Don't store in this in `Body` + BlockTailTemp(BlockTailInfo), /// A temporary created during the pass `Derefer` to avoid it's retagging DerefTemp, /// A temporary created for borrow checking. FakeBorrow, + /// A local without anything interesting about it. + Boring, } impl<'tcx> LocalDecl<'tcx> { + pub fn local_info(&self) -> &LocalInfo<'tcx> { + &**self.local_info.as_ref().assert_crate_local() + } + /// Returns `true` only if local is a binding that can itself be /// made mutable via the addition of the `mut` keyword, namely /// something like the occurrences of `x` in: @@ -913,15 +919,15 @@ impl<'tcx> LocalDecl<'tcx> { /// - or `match ... { C(x) => ... }` pub fn can_be_made_mutable(&self) -> bool { matches!( - self.local_info, - Some(box LocalInfo::User(ClearCrossCrate::Set( + self.local_info(), + LocalInfo::User( BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, opt_match_place: _, pat_span: _, }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm), - ))) + ) ) } @@ -930,15 +936,15 @@ impl<'tcx> LocalDecl<'tcx> { /// mutable bindings, but the inverse does not necessarily hold). pub fn is_nonref_binding(&self) -> bool { matches!( - self.local_info, - Some(box LocalInfo::User(ClearCrossCrate::Set( + self.local_info(), + LocalInfo::User( BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, opt_match_place: _, pat_span: _, }) | BindingForm::ImplicitSelf(_), - ))) + ) ) } @@ -946,38 +952,35 @@ impl<'tcx> LocalDecl<'tcx> { /// parameter declared by the user. #[inline] pub fn is_user_variable(&self) -> bool { - matches!(self.local_info, Some(box LocalInfo::User(_))) + matches!(self.local_info(), LocalInfo::User(_)) } /// Returns `true` if this is a reference to a variable bound in a `match` /// expression that is used to access said variable for the guard of the /// match arm. pub fn is_ref_for_guard(&self) -> bool { - matches!( - self.local_info, - Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) - ) + matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard)) } /// Returns `Some` if this is a reference to a static item that is used to /// access that static. pub fn is_ref_to_static(&self) -> bool { - matches!(self.local_info, Some(box LocalInfo::StaticRef { .. })) + matches!(self.local_info(), LocalInfo::StaticRef { .. }) } /// Returns `Some` if this is a reference to a thread-local static item that is used to /// access that static. pub fn is_ref_to_thread_local(&self) -> bool { - match self.local_info { - Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local, + match self.local_info() { + LocalInfo::StaticRef { is_thread_local, .. } => *is_thread_local, _ => false, } } /// Returns `true` if this is a DerefTemp pub fn is_deref_temp(&self) -> bool { - match self.local_info { - Some(box LocalInfo::DerefTemp) => return true, + match self.local_info() { + LocalInfo::DerefTemp => return true, _ => (), } return false; @@ -1001,9 +1004,8 @@ impl<'tcx> LocalDecl<'tcx> { pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self { LocalDecl { mutability: Mutability::Mut, - local_info: None, + local_info: ClearCrossCrate::Set(Box::new(LocalInfo::Boring)), internal: false, - is_block_tail: None, ty, user_ty: None, source_info, @@ -1023,14 +1025,6 @@ impl<'tcx> LocalDecl<'tcx> { self.mutability = Mutability::Not; self } - - /// Converts `self` into same `LocalDecl` except tagged as internal temporary. - #[inline] - pub fn block_tail(mut self, info: BlockTailInfo) -> Self { - assert!(self.is_block_tail.is_none()); - self.is_block_tail = Some(info); - self - } } #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] @@ -1274,6 +1268,13 @@ impl<'tcx> BasicBlockData<'tcx> { } impl<O> AssertKind<O> { + /// Returns true if this an overflow checking assertion controlled by -C overflow-checks. + pub fn is_optional_overflow_check(&self) -> bool { + use AssertKind::*; + use BinOp::*; + matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..)) + } + /// Getting a description does not require `O` to be printable, and does not /// require allocation. /// The caller is expected to handle `BoundsCheck` separately. @@ -1966,7 +1967,8 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::PtrToPtr | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress - | CastKind::DynStar, + | CastKind::DynStar + | CastKind::Transmute, _, _, ) @@ -1998,16 +2000,6 @@ impl BorrowKind { } } -impl BinOp { - /// The checkable operators are those whose overflow checking behavior is controlled by - /// -Coverflow-checks option. The remaining operators have either no overflow conditions (e.g., - /// BitAnd, BitOr, BitXor) or are always checked for overflow (e.g., Div, Rem). - pub fn is_checkable(self) -> bool { - use self::BinOp::*; - matches!(self, Add | Sub | Mul | Shl | Shr) - } -} - impl<'tcx> Debug for Rvalue<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::Rvalue::*; @@ -2534,7 +2526,7 @@ impl<'tcx> ConstantKind<'tcx> { let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) && let Some(parent_did) = parent_hir_id.as_owner() { - InternalSubsts::identity_for_item(tcx, parent_did.to_def_id()) + InternalSubsts::identity_for_item(tcx, parent_did) } else { List::empty() }; @@ -2563,7 +2555,7 @@ impl<'tcx> ConstantKind<'tcx> { Self::Unevaluated( UnevaluatedConst { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs: InternalSubsts::identity_for_item(tcx, def.did), promoted: None, }, ty, @@ -3091,7 +3083,7 @@ mod size_asserts { use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(BasicBlockData<'_>, 144); - static_assert_size!(LocalDecl<'_>, 56); + static_assert_size!(LocalDecl<'_>, 40); static_assert_size!(Statement<'_>, 32); static_assert_size!(StatementKind<'_>, 16); static_assert_size!(Terminator<'_>, 112); diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index 24fe3b47256..eb860c04de2 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -72,12 +72,12 @@ impl<'tcx> MirPatch<'tcx> { &mut self, ty: Ty<'tcx>, span: Span, - local_info: Option<Box<LocalInfo<'tcx>>>, + local_info: LocalInfo<'tcx>, ) -> Local { let index = self.next_local; self.next_local += 1; let mut new_decl = LocalDecl::new(ty, span).internal(); - new_decl.local_info = local_info; + **new_decl.local_info.as_mut().assert_crate_local() = local_info; self.new_locals.push(new_decl); Local::new(index as usize) } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index d85d68870d7..786c2e9cd94 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,8 +2,8 @@ use crate::mir::{Body, ConstantKind, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -227,7 +227,7 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>, pub used_mut_upvars: SmallVec<[Field; 8]>, pub tainted_by_errors: Option<ErrorGuaranteed>, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 2205c42f7ce..bbd913d071d 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -78,7 +78,8 @@ pub enum MirPhase { /// MIR, this is UB. /// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way /// that Rust itself has them. Where exactly these are is generally subject to change, and so we - /// don't document this here. Runtime MIR has all retags explicit. + /// don't document this here. Runtime MIR has most retags explicit (though implicit retags + /// can still occur at `Rvalue::{Ref,AddrOf}`). /// - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has /// access to. This occurs in generator bodies. Such locals do not behave like other locals, /// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals - @@ -646,8 +647,7 @@ pub enum TerminatorKind<'tcx> { /// When overflow checking is disabled and this is run-time MIR (as opposed to compile-time MIR /// that is used for CTFE), the following variants of this terminator behave as `goto target`: /// - `OverflowNeg(..)`, - /// - `Overflow(op, ..)` if op is a "checkable" operation (add, sub, mul, shl, shr, but NOT - /// div or rem). + /// - `Overflow(op, ..)` if op is add, sub, mul, shl, shr, but NOT div or rem. Assert { cond: Operand<'tcx>, expected: bool, @@ -1081,7 +1081,7 @@ pub enum Rvalue<'tcx> { /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. /// /// For addition, subtraction, and multiplication on integers the error condition is set when - /// the infinite precision result would be unequal to the actual result. + /// the infinite precision result would not be equal to the actual result. /// /// Other combinations of types and operators are unsupported. CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), @@ -1156,6 +1156,13 @@ pub enum CastKind { IntToFloat, PtrToPtr, FnPtrToPtr, + /// Reinterpret the bits of the input as a different type. + /// + /// MIR is well-formed if the input and output types have different sizes, + /// but running a transmute between differently-sized types is UB. + /// + /// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`]. + Transmute, } #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -1166,7 +1173,7 @@ pub enum AggregateKind<'tcx> { Tuple, /// The second field is the variant index. It's equal to 0 for struct - /// and union expressions. The fourth field is + /// and union expressions. The last field is the /// active field number and is present only for union expressions /// -- e.g., for a union expression `SomeUnion { c: .. }`, the /// active field index would identity the field `c` diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index cbeacf21c19..cffdd7ff37f 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -804,7 +804,6 @@ macro_rules! make_mir_visitor { source_info, internal: _, local_info: _, - is_block_tail: _, } = local_decl; self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl { diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 6e961a775c1..ca65fbc2fd4 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -13,6 +13,10 @@ use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCa use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; +/// Placeholder for `CrateNum`'s "local" counterpart +#[derive(Copy, Clone, Debug)] +pub struct LocalCrate; + /// The `Key` trait controls what types can legally be used as the key /// for a query. pub trait Key: Sized { @@ -26,10 +30,6 @@ pub trait Key: Sized { // r-a issue: <https://github.com/rust-lang/rust-analyzer/issues/13693> type CacheSelector; - /// Given an instance of this key, what crate is it referring to? - /// This is used to find the provider. - fn query_crate_is_local(&self) -> bool; - /// In the event that a cycle occurs, if no explicit span has been /// given for a query with key `self`, what span should we use? fn default_span(&self, tcx: TyCtxt<'_>) -> Span; @@ -45,14 +45,17 @@ pub trait Key: Sized { } } +pub trait AsLocalKey: Key { + type LocalKey; + + /// Given an instance of this key, what crate is it referring to? + /// This is used to find the provider. + fn as_local_key(&self) -> Option<Self::LocalKey>; +} + impl Key for () { type CacheSelector = SingleCacheSelector; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -61,23 +64,22 @@ impl Key for () { impl<'tcx> Key for ty::InstanceDef<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().is_local() - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } } -impl<'tcx> Key for ty::Instance<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; +impl<'tcx> AsLocalKey for ty::InstanceDef<'tcx> { + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().is_local() + fn as_local_key(&self) -> Option<Self::LocalKey> { + self.def_id().is_local().then(|| *self) } +} + +impl<'tcx> Key for ty::Instance<'tcx> { + type CacheSelector = DefaultCacheSelector<Self>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -87,11 +89,6 @@ impl<'tcx> Key for ty::Instance<'tcx> { impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.instance.default_span(tcx) } @@ -100,11 +97,6 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -113,11 +105,6 @@ impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) { impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -126,25 +113,27 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { impl Key for CrateNum { type CacheSelector = VecCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - *self == LOCAL_CRATE - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } } -impl Key for OwnerId { - type CacheSelector = VecCacheSelector<Self>; +impl AsLocalKey for CrateNum { + type LocalKey = LocalCrate; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option<Self::LocalKey> { + (*self == LOCAL_CRATE).then_some(LocalCrate) } +} + +impl Key for OwnerId { + type CacheSelector = VecCacheSelector<Self>; + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) } + fn key_as_def_id(&self) -> Option<DefId> { Some(self.to_def_id()) } @@ -153,13 +142,10 @@ impl Key for OwnerId { impl Key for LocalDefId { type CacheSelector = VecCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) } + fn key_as_def_id(&self) -> Option<DefId> { Some(self.to_def_id()) } @@ -168,26 +154,28 @@ impl Key for LocalDefId { impl Key for DefId { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) } + #[inline(always)] fn key_as_def_id(&self) -> Option<DefId> { Some(*self) } } -impl Key for ty::WithOptConstParam<LocalDefId> { - type CacheSelector = DefaultCacheSelector<Self>; +impl AsLocalKey for DefId { + type LocalKey = LocalDefId; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option<Self::LocalKey> { + self.as_local() } +} + +impl Key for ty::WithOptConstParam<LocalDefId> { + type CacheSelector = DefaultCacheSelector<Self>; + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.did.default_span(tcx) } @@ -196,10 +184,6 @@ impl Key for ty::WithOptConstParam<LocalDefId> { impl Key for SimplifiedType { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -208,10 +192,6 @@ impl Key for SimplifiedType { impl Key for (DefId, DefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -220,10 +200,6 @@ impl Key for (DefId, DefId) { impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -232,10 +208,6 @@ impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { impl Key for (DefId, LocalDefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -244,10 +216,6 @@ impl Key for (DefId, LocalDefId) { impl Key for (LocalDefId, DefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -256,10 +224,6 @@ impl Key for (LocalDefId, DefId) { impl Key for (LocalDefId, LocalDefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -268,26 +232,19 @@ impl Key for (LocalDefId, LocalDefId) { impl Key for (DefId, Option<Ident>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0) } + #[inline(always)] fn key_as_def_id(&self) -> Option<DefId> { Some(self.0) } } -impl Key for (DefId, LocalDefId, Ident) { +impl Key for (LocalDefId, LocalDefId, Ident) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -296,34 +253,40 @@ impl Key for (DefId, LocalDefId, Ident) { impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0 == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } } -impl Key for (CrateNum, SimplifiedType) { - type CacheSelector = DefaultCacheSelector<Self>; +impl AsLocalKey for (CrateNum, DefId) { + type LocalKey = DefId; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0 == LOCAL_CRATE + fn as_local_key(&self) -> Option<Self::LocalKey> { + (self.0 == LOCAL_CRATE).then(|| self.1) } +} + +impl Key for (CrateNum, SimplifiedType) { + type CacheSelector = DefaultCacheSelector<Self>; + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } } -impl Key for (DefId, SimplifiedType) { - type CacheSelector = DefaultCacheSelector<Self>; +impl AsLocalKey for (CrateNum, SimplifiedType) { + type LocalKey = SimplifiedType; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option<Self::LocalKey> { + (self.0 == LOCAL_CRATE).then(|| self.1) } +} + +impl Key for (DefId, SimplifiedType) { + type CacheSelector = DefaultCacheSelector<Self>; + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -332,10 +295,6 @@ impl Key for (DefId, SimplifiedType) { impl<'tcx> Key for SubstsRef<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -344,10 +303,6 @@ impl<'tcx> Key for SubstsRef<'tcx> { impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -356,10 +311,6 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - (self.0).def.did.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { (self.0).def.did.default_span(tcx) } @@ -368,10 +319,6 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -380,10 +327,6 @@ impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.1.def_id().krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.1.def_id()) } @@ -392,10 +335,6 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -404,10 +343,6 @@ impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -416,10 +351,6 @@ impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { impl<'tcx> Key for ty::PolyTraitRef<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } @@ -428,10 +359,6 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } @@ -440,10 +367,6 @@ impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.def_id().krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0.def_id()) } @@ -452,10 +375,6 @@ impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for GenericArg<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -464,10 +383,6 @@ impl<'tcx> Key for GenericArg<'tcx> { impl<'tcx> Key for mir::ConstantKind<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -476,10 +391,6 @@ impl<'tcx> Key for mir::ConstantKind<'tcx> { impl<'tcx> Key for ty::Const<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -488,13 +399,10 @@ impl<'tcx> Key for ty::Const<'tcx> { impl<'tcx> Key for Ty<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } + fn ty_adt_id(&self) -> Option<DefId> { match self.kind() { ty::Adt(adt, _) => Some(adt.did()), @@ -506,10 +414,6 @@ impl<'tcx> Key for Ty<'tcx> { impl<'tcx> Key for TyAndLayout<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -518,10 +422,6 @@ impl<'tcx> Key for TyAndLayout<'tcx> { impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -530,10 +430,6 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -542,10 +438,6 @@ impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> { impl<'tcx> Key for ty::ParamEnv<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -554,10 +446,6 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.value.query_crate_is_local() - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) } @@ -566,10 +454,6 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { impl Key for Symbol { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -578,10 +462,6 @@ impl Key for Symbol { impl Key for Option<Symbol> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -589,14 +469,9 @@ impl Key for Option<Symbol> { /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. -impl<'tcx, T> Key for Canonical<'tcx, T> { +impl<'tcx, T: Clone> Key for Canonical<'tcx, T> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -605,11 +480,6 @@ impl<'tcx, T> Key for Canonical<'tcx, T> { impl Key for (Symbol, u32, u32) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -618,11 +488,6 @@ impl Key for (Symbol, u32, u32) { impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -631,11 +496,6 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -644,11 +504,6 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -657,11 +512,6 @@ impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) { impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -670,11 +520,6 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) { impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -683,11 +528,6 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { impl Key for HirId { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.hir().span(*self) } @@ -702,10 +542,6 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; // Just forward to `Ty<'tcx>` - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 75f05c4af23..9203dd59a7e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -8,7 +8,7 @@ use crate::ty::{self, print::describe_as_module, TyCtxt}; use rustc_span::def_id::LOCAL_CRATE; mod keys; -pub use keys::Key; +pub use keys::{AsLocalKey, Key, LocalCrate}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method @@ -191,6 +191,7 @@ rustc_queries! { { desc { "determine whether the opaque is a type-alias impl trait" } separate_provide_extern + feedable } query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> @@ -638,7 +639,7 @@ rustc_queries! { /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + query type_param_predicates(key: (LocalDefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) } } @@ -784,7 +785,7 @@ rustc_queries! { /// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it /// creates and returns the associated items that correspond to each impl trait in return position /// of the implemented trait. - query associated_items_for_impl_trait_in_trait(fn_def_id: DefId) -> &'tcx [DefId] { + query associated_types_for_impl_traits_in_associated_fn(fn_def_id: DefId) -> &'tcx [DefId] { desc { |tcx| "creating associated items for impl trait in trait returned by `{}`", tcx.def_path_str(fn_def_id) } cache_on_disk_if { fn_def_id.is_local() } separate_provide_extern @@ -792,10 +793,9 @@ rustc_queries! { /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding /// associated item. - query associated_item_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { + query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { desc { |tcx| "creates the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } cache_on_disk_if { true } - separate_provide_extern } /// Given an `impl_id`, return the trait it implements. @@ -2116,7 +2116,7 @@ rustc_queries! { desc { "raw operations for metadata file access" } } - query crate_for_resolver((): ()) -> &'tcx Steal<rustc_ast::ast::Crate> { + query crate_for_resolver((): ()) -> &'tcx Steal<(rustc_ast::Crate, rustc_ast::AttrVec)> { feedable no_hash desc { "the ast before macro expansion and name resolution" } @@ -2215,7 +2215,7 @@ rustc_queries! { } /// Used in `super_combine_consts` to ICE if the type of the two consts are definitely not going to end up being - /// equal to eachother. This might return `Ok` even if the types are unequal, but will never return `Err` if + /// equal to eachother. This might return `Ok` even if the types are not equal, but will never return `Err` if /// the types might be equal. query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> { desc { "check whether two const param are definitely not equal to eachother"} diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 6231dd9b6f5..833402abfc4 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -305,8 +305,6 @@ pub enum ObligationCauseCode<'tcx> { SizedReturnType, /// Yield type must be `Sized`. SizedYieldType, - /// Box expression result type must be `Sized`. - SizedBoxType, /// Inline asm operand type must be `Sized`. InlineAsmSized, /// `[expr; N]` requires `type_of(expr): Copy`. @@ -899,6 +897,9 @@ pub enum ObjectSafetyViolation { /// (e.g., `trait Foo : Bar<Self>`). SupertraitSelf(SmallVec<[Span; 1]>), + // Supertrait has a non-lifetime `for<T>` binder. + SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>), + /// Method has something illegal. Method(Symbol, MethodViolationCode, Span), @@ -921,6 +922,9 @@ impl ObjectSafetyViolation { .into() } } + ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => { + format!("where clause cannot reference non-lifetime `for<...>` variables").into() + } ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{}` has no `self` parameter", name).into() } @@ -971,7 +975,9 @@ impl ObjectSafetyViolation { pub fn solution(&self, err: &mut Diagnostic) { match self { - ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {} + ObjectSafetyViolation::SizedSelf(_) + | ObjectSafetyViolation::SupertraitSelf(_) + | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => {} ObjectSafetyViolation::Method( name, MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))), @@ -1025,7 +1031,8 @@ impl ObjectSafetyViolation { // diagnostics use a `note` instead of a `span_label`. match self { ObjectSafetyViolation::SupertraitSelf(spans) - | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), + | ObjectSafetyViolation::SizedSelf(spans) + | ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(), ObjectSafetyViolation::AssocConst(_, span) | ObjectSafetyViolation::GAT(_, span) | ObjectSafetyViolation::Method(_, _, span) diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 92d3e73e683..512d67f34b9 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -63,15 +63,14 @@ impl Certainty { (Certainty::Yes, Certainty::Yes) => Certainty::Yes, (Certainty::Yes, Certainty::Maybe(_)) => other, (Certainty::Maybe(_), Certainty::Yes) => self, - (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => { - Certainty::Maybe(MaybeCause::Overflow) - } - // If at least one of the goals is ambiguous, hide the overflow as the ambiguous goal - // may still result in failure. - (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(_)) - | (Certainty::Maybe(_), Certainty::Maybe(MaybeCause::Ambiguity)) => { + (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => { Certainty::Maybe(MaybeCause::Ambiguity) } + (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow)) + | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity)) + | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => { + Certainty::Maybe(MaybeCause::Overflow) + } } } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 42101f6b931..bcedae233d9 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -4,7 +4,7 @@ use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_macros::HashStable; use std::fmt; @@ -83,7 +83,7 @@ impl<'tcx> Const<'tcx> { None => tcx.mk_const( ty::UnevaluatedConst { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs: InternalSubsts::identity_for_item(tcx, def.did), }, ty, ), @@ -265,8 +265,8 @@ impl<'tcx> Const<'tcx> { } } -pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Const<'_>> { - let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) { +pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Const<'_>> { + let default_def_id = match tcx.hir().get_by_def_id(def_id) { hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { default: Some(ac), .. }, .. diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index eecd78ab6c0..a7f38884ebc 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -237,7 +237,7 @@ impl ScalarInt { } /// Tries to convert the `ScalarInt` to an unsigned integer of the given size. - /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the + /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the /// `ScalarInt`s size in that case. #[inline] pub fn try_to_uint(self, size: Size) -> Result<u128, Size> { @@ -297,7 +297,7 @@ impl ScalarInt { } /// Tries to convert the `ScalarInt` to a signed integer of the given size. - /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the + /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the /// `ScalarInt`s size in that case. #[inline] pub fn try_to_int(self, size: Size) -> Result<i128, Size> { @@ -306,35 +306,35 @@ impl ScalarInt { } /// Tries to convert the `ScalarInt` to i8. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 1 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i8(self) -> Result<i8, Size> { self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to i16. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 2 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i16(self) -> Result<i16, Size> { self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to i32. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 4 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i32(self) -> Result<i32, Size> { self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to i64. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 8 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i64(self) -> Result<i64, Size> { self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to i128. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 16 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i128(self) -> Result<i128, Size> { self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap()) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d5ba0785fa6..a1c1acc4a25 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -15,6 +15,7 @@ use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{ Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted, }; +use crate::query::LocalCrate; use crate::thir::Thir; use crate::traits; use crate::traits::solve; @@ -27,7 +28,7 @@ use crate::ty::{ TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::intern::Interned; @@ -71,6 +72,7 @@ use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{CollectAndApply, DynKind, Interner, TypeFlags}; use std::any::Any; +use std::assert_matches::debug_assert_matches; use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; @@ -2049,6 +2051,12 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> { + debug_assert_matches!( + (kind, self.def_kind(alias_ty.def_id)), + (ty::Opaque, DefKind::OpaqueTy) + | (ty::Projection, DefKind::AssocTy) + | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder) + ); self.mk_ty_from_kind(Alias(kind, alias_ty)) } @@ -2511,16 +2519,11 @@ pub fn provide(providers: &mut ty::query::Providers) { providers.extern_mod_stmt_cnum = |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); - providers.is_panic_runtime = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime) - }; - providers.is_compiler_builtins = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins) - }; - providers.has_panic_handler = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); + providers.is_panic_runtime = + |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); + providers.is_compiler_builtins = + |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); + providers.has_panic_handler = |tcx, LocalCrate| { // We want to check if the panic handler was defined in this crate tcx.lang_items().panic_impl().map_or(false, |did| did.is_local()) }; diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index ee505742be9..669d50a7fda 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -56,7 +56,15 @@ pub enum TreatParams { AsCandidateKey, /// Treat parameters as placeholders in the given environment. This is the /// correct mode for *lookup*, as during candidate selection. + /// + /// This also treats projections with inference variables as infer vars + /// since they could be further normalized. ForLookup, + /// Treat parameters as placeholders in the given environment. This is the + /// correct mode for *lookup*, as during candidate selection. + /// + /// N.B. during deep rejection, this acts identically to `ForLookup`. + NextSolverLookup, } /// During fast-rejection, we have the choice of treating projection types @@ -64,13 +72,6 @@ pub enum TreatParams { /// to be normalized/rigid. #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum TreatProjections { - /// In candidates, we may be able to normalize the projection - /// after instantiating the candidate and equating it with a goal. - /// - /// We must assume that the `impl<T> Trait<T> for <T as Id>::This` - /// can apply to all self types so we don't return a simplified type - /// for `<T as Id>::This`. - AsCandidateKey, /// In the old solver we don't try to normalize projections /// when looking up impls and only access them by using the /// current self type. This means that if the self type is @@ -107,7 +108,6 @@ pub fn simplify_type<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, treat_params: TreatParams, - treat_projections: TreatProjections, ) -> Option<SimplifiedType> { match *ty.kind() { ty::Bool => Some(BoolSimplifiedType), @@ -136,13 +136,20 @@ pub fn simplify_type<'tcx>( ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), ty::Placeholder(..) => Some(PlaceholderSimplifiedType), ty::Param(_) => match treat_params { - TreatParams::ForLookup => Some(PlaceholderSimplifiedType), + TreatParams::ForLookup | TreatParams::NextSolverLookup => { + Some(PlaceholderSimplifiedType) + } TreatParams::AsCandidateKey => None, }, - ty::Alias(..) => match treat_projections { - TreatProjections::ForLookup if !ty.needs_infer() => Some(PlaceholderSimplifiedType), - TreatProjections::NextSolverLookup => Some(PlaceholderSimplifiedType), - TreatProjections::AsCandidateKey | TreatProjections::ForLookup => None, + ty::Alias(..) => match treat_params { + // When treating `ty::Param` as a placeholder, projections also + // don't unify with anything else as long as they are fully normalized. + // + // We will have to be careful with lazy normalization here. + // FIXME(lazy_normalization): This is probably not right... + TreatParams::ForLookup if !ty.has_non_region_infer() => Some(PlaceholderSimplifiedType), + TreatParams::NextSolverLookup => Some(PlaceholderSimplifiedType), + TreatParams::ForLookup | TreatParams::AsCandidateKey => None, }, ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, @@ -310,7 +317,7 @@ impl DeepRejectCtxt { // Depending on the value of `treat_obligation_params`, we either // treat generic parameters like placeholders or like inference variables. ty::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup => false, + TreatParams::ForLookup | TreatParams::NextSolverLookup => false, TreatParams::AsCandidateKey => true, }, @@ -348,7 +355,7 @@ impl DeepRejectCtxt { let k = impl_ct.kind(); match obligation_ct.kind() { ty::ConstKind::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup => false, + TreatParams::ForLookup | TreatParams::NextSolverLookup => false, TreatParams::AsCandidateKey => true, }, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 91241ff404f..5a6ee123811 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -288,7 +288,7 @@ impl FlagComputation { self.add_ty(ty); } ty::PredicateKind::Ambiguous => {} - ty::PredicateKind::AliasEq(t1, t2) => { + ty::PredicateKind::AliasRelate(t1, t2, _) => { self.add_term(t1); self.add_term(t2); } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index d66f436f947..6205e2bf24d 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -51,9 +51,7 @@ where // Region folder impl<'tcx> TyCtxt<'tcx> { - /// Folds the escaping and free regions in `value` using `f`, and - /// sets `skipped_regions` to true if any late-bound region was found - /// and skipped. + /// Folds the escaping and free regions in `value` using `f`. pub fn fold_regions<T>( self, value: T, @@ -64,17 +62,6 @@ impl<'tcx> TyCtxt<'tcx> { { value.fold_with(&mut RegionFolder::new(self, &mut f)) } - - pub fn super_fold_regions<T>( - self, - value: T, - mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, - ) -> T - where - T: TypeSuperFoldable<TyCtxt<'tcx>>, - { - value.super_fold_with(&mut RegionFolder::new(self, &mut f)) - } } /// Folds over the substructure of a type, visiting its component diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index f4028a5a9f6..aa10a651c07 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -187,7 +187,11 @@ impl<'tcx> InstanceDef<'tcx> { } #[inline] - pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> { + pub fn get_attrs( + &self, + tcx: TyCtxt<'tcx>, + attr: Symbol, + ) -> impl Iterator<Item = &'tcx rustc_ast::Attribute> { tcx.get_attrs(self.def_id(), attr) } @@ -781,6 +785,12 @@ fn needs_fn_once_adapter_shim( #[derive(Debug, Copy, Clone, Eq, PartialEq, Decodable, Encodable, HashStable)] pub struct UnusedGenericParams(FiniteBitSet<u32>); +impl Default for UnusedGenericParams { + fn default() -> Self { + UnusedGenericParams::new_all_used() + } +} + impl UnusedGenericParams { pub fn new_all_unused(amount: u32) -> Self { let mut bitset = FiniteBitSet::new_empty(); @@ -807,4 +817,12 @@ impl UnusedGenericParams { pub fn all_used(&self) -> bool { self.0.is_empty() } + + pub fn bits(&self) -> u32 { + self.0.0 + } + + pub fn from_bits(bits: u32) -> UnusedGenericParams { + UnusedGenericParams(FiniteBitSet(bits)) + } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 04d7de531c2..e3cd5cca785 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -543,7 +543,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(Clause::TypeOutlives(_)) | PredicateKind::Clause(Clause::Projection(_)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::ObjectSafe(_) | PredicateKind::ClosureKind(_, _, _) | PredicateKind::Subtype(_) @@ -640,7 +640,23 @@ pub enum PredicateKind<'tcx> { /// This predicate requires two terms to be equal to eachother. /// /// Only used for new solver - AliasEq(Term<'tcx>, Term<'tcx>), + AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, Debug)] +pub enum AliasRelationDirection { + Equate, + Subtype, +} + +impl std::fmt::Display for AliasRelationDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AliasRelationDirection::Equate => write!(f, " == "), + AliasRelationDirection::Subtype => write!(f, " <: "), + } + } } /// The crate outlives map is computed during typeck and contains the @@ -976,11 +992,11 @@ impl<'tcx> Term<'tcx> { } } - /// This function returns `None` for `AliasKind::Opaque`. + /// This function returns the inner `AliasTy` if this term is a projection. /// /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly /// deal with constants. - pub fn to_alias_term_no_opaque(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { + pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { match self.unpack() { TermKind::Ty(ty) => match ty.kind() { ty::Alias(kind, alias_ty) => match kind { @@ -1035,6 +1051,21 @@ impl<'tcx> TermKind<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum ParamTerm { + Ty(ParamTy), + Const(ParamConst), +} + +impl ParamTerm { + pub fn index(self) -> usize { + match self { + ParamTerm::Ty(ty) => ty.index as usize, + ParamTerm::Const(ct) => ct.index as usize, + } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1128,6 +1159,13 @@ impl<'tcx, T> ToPredicate<'tcx, T> for T { } } +impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1142,6 +1180,13 @@ impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { } } +impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1192,7 +1237,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(Clause::Projection(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -1213,7 +1258,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(Clause::Trait(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -1235,7 +1280,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Trait(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) | PredicateKind::Clause(Clause::Projection(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -1385,7 +1430,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { // lifetimes with 'static and remapping only those used in the // `impl Trait` return type, resulting in the parameters // shifting. - let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let id_substs = InternalSubsts::identity_for_item(tcx, def_id); debug!(?id_substs); // This zip may have several times the same lifetime in `substs` paired with a different @@ -2027,7 +2072,6 @@ impl<'tcx> FieldDef { } } -pub type Attributes<'tcx> = impl Iterator<Item = &'tcx ast::Attribute>; #[derive(Debug, PartialEq, Eq)] pub enum ImplOverlapKind { /// These impls are always allowed to overlap. @@ -2375,7 +2419,12 @@ impl<'tcx> TyCtxt<'tcx> { } /// Gets all attributes with the given name. - pub fn get_attrs(self, did: DefId, attr: Symbol) -> ty::Attributes<'tcx> { + pub fn get_attrs( + self, + did: impl Into<DefId>, + attr: Symbol, + ) -> impl Iterator<Item = &'tcx ast::Attribute> { + let did: DefId = did.into(); let filter_fn = move |a: &&ast::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn) @@ -2386,8 +2435,9 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> { + pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> { if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { + let did: DefId = did.into(); bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); } else { self.get_attrs(did, attr).next() @@ -2395,7 +2445,8 @@ impl<'tcx> TyCtxt<'tcx> { } /// Determines whether an item is annotated with an attribute. - pub fn has_attr(self, did: DefId, attr: Symbol) -> bool { + pub fn has_attr(self, did: impl Into<DefId>, attr: Symbol) -> bool { + let did: DefId = did.into(); if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) { bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); } else { @@ -2505,7 +2556,7 @@ impl<'tcx> TyCtxt<'tcx> { ident } - // FIXME(vincenzoapalzzo): move the HirId to a LocalDefId + // FIXME(vincenzopalazzo): move the HirId to a LocalDefId pub fn adjust_ident_and_get_scope( self, mut ident: Ident, @@ -2552,12 +2603,18 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait)) } - pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId { - while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { - debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); - def_id = self.parent(def_id); + pub fn impl_trait_in_trait_parent_fn(self, mut def_id: DefId) -> DefId { + match self.opt_rpitit_info(def_id) { + Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) + | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id, + None => { + while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { + debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); + def_id = self.parent(def_id); + } + def_id + } } - def_id } pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { @@ -2572,6 +2629,12 @@ impl<'tcx> TyCtxt<'tcx> { let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; + if self.lower_impl_trait_in_trait_to_assoc_ty() { + return !self + .associated_types_for_impl_traits_in_associated_fn(trait_item_def_id) + .is_empty(); + } + // FIXME(RPITIT): This does a somewhat manual walk through the signature // of the trait fn to look for any RPITITs, but that's kinda doing a lot // of work. We can probably remove this when we refactor RPITITs to be diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b3139d23d36..de4c703107e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -704,7 +704,11 @@ pub trait PrettyPrinter<'tcx>: ty::BoundTyKind::Anon(bv) => { self.pretty_print_bound_var(debruijn, ty::BoundVar::from_u32(bv))? } - ty::BoundTyKind::Param(_, s) => p!(write("{}", s)), + ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { + true if debruijn == ty::INNERMOST => p!(write("^{}", s)), + true => p!(write("^{}_{}", debruijn.index(), s)), + false => p!(write("{}", s)), + }, }, ty::Adt(def, substs) => { p!(print_def_path(def.did(), substs)); @@ -728,7 +732,7 @@ pub trait PrettyPrinter<'tcx>: } ty::Alias(ty::Projection, ref data) => { if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get())) - && self.tcx().def_kind(data.def_id) == DefKind::ImplTraitPlaceholder + && self.tcx().is_impl_trait_in_trait(data.def_id) { return self.pretty_print_opaque_impl_type(data.def_id, data.substs); } else { @@ -2847,7 +2851,7 @@ define_print_and_forward_display! { p!("the type `", print(ty), "` is found in the environment") } ty::PredicateKind::Ambiguous => p!("ambiguous"), - ty::PredicateKind::AliasEq(t1, t2) => p!(print(t1), " == ", print(t2)), + ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)), } } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 05219efe5f5..30246fe4dbe 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -17,7 +17,7 @@ use crate::mir::interpret::{ }; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; -use crate::query::Key; +use crate::query::{AsLocalKey, Key}; use crate::thir; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, @@ -151,6 +151,20 @@ macro_rules! query_if_arena { }; } +/// If `separate_provide_if_extern`, then the key can be projected to its +/// local key via `<$K as AsLocalKey>::LocalKey`. +macro_rules! local_key_if_separate_extern { + ([] $($K:tt)*) => { + $($K)* + }; + ([(separate_provide_extern) $($rest:tt)*] $($K:tt)*) => { + <$($K)* as AsLocalKey>::LocalKey + }; + ([$other:tt $($modifiers:tt)*] $($K:tt)*) => { + local_key_if_separate_extern!([$($modifiers)*] $($K)*) + }; +} + macro_rules! separate_provide_extern_decl { ([][$name:ident]) => { () @@ -212,6 +226,12 @@ macro_rules! define_callbacks { $(pub type $name<'tcx> = $($K)*;)* } #[allow(nonstandard_style, unused_lifetimes)] + pub mod query_keys_local { + use super::*; + + $(pub type $name<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);)* + } + #[allow(nonstandard_style, unused_lifetimes)] pub mod query_values { use super::*; @@ -385,7 +405,7 @@ macro_rules! define_callbacks { pub struct Providers { $(pub $name: for<'tcx> fn( TyCtxt<'tcx>, - query_keys::$name<'tcx>, + query_keys_local::$name<'tcx>, ) -> query_provided::$name<'tcx>,)* } @@ -395,17 +415,14 @@ macro_rules! define_callbacks { impl Default for Providers { fn default() -> Self { - use crate::query::Key; - Providers { $($name: |_, key| bug!( - "`tcx.{}({:?})` is not supported for {} crate;\n\ + "`tcx.{}({:?})` is not supported for this key;\n\ hint: Queries can be either made to the local crate, or the external crate. \ This error means you tried to use it for one that's not supported.\n\ If that's not the case, {} was likely never assigned to a provider function.\n", stringify!($name), key, - if key.query_crate_is_local() { "local" } else { "external" }, stringify!($name), ),)* } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index ef643531bb2..c6bb8146795 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -177,7 +177,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { write!(f, "TypeWellFormedFromEnv({:?})", ty) } ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"), - ty::PredicateKind::AliasEq(t1, t2) => write!(f, "AliasEq({t1:?}, {t2:?})"), + ty::PredicateKind::AliasRelate(t1, t2, dir) => { + write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})") + } } } } @@ -250,6 +252,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::AssocItem, crate::ty::AssocKind, crate::ty::AliasKind, + crate::ty::AliasRelationDirection, crate::ty::Placeholder<crate::ty::BoundRegionKind>, crate::ty::Placeholder<crate::ty::BoundTyKind>, crate::ty::ClosureKind, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 52d114bae30..35a581d314c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -23,7 +23,7 @@ use rustc_macros::HashStable; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use rustc_target::abi::VariantIdx; -use rustc_target::spec::abi; +use rustc_target::spec::abi::{self, Abi}; use std::borrow::Cow; use std::cmp::Ordering; use std::fmt; @@ -1288,7 +1288,7 @@ impl<'tcx> AliasTy<'tcx> { match tcx.def_kind(self.def_id) { DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), DefKind::ImplTraitPlaceholder => { - tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id)) + tcx.parent(tcx.impl_trait_in_trait_parent_fn(self.def_id)) } kind => bug!("expected a projection AliasTy; found {kind:?}"), } @@ -1403,6 +1403,18 @@ impl<'tcx> PolyFnSig<'tcx> { pub fn abi(&self) -> abi::Abi { self.skip_binder().abi } + + pub fn is_fn_trait_compatible(&self) -> bool { + matches!( + self.skip_binder(), + ty::FnSig { + unsafety: rustc_hir::Unsafety::Normal, + abi: Abi::Rust, + c_variadic: false, + .. + } + ) + } } pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>; @@ -1914,11 +1926,6 @@ impl<'tcx> Ty<'tcx> { } #[inline] - pub fn is_region_ptr(self) -> bool { - matches!(self.kind(), Ref(..)) - } - - #[inline] pub fn is_mutable_ptr(self) -> bool { matches!( self.kind(), @@ -1944,7 +1951,7 @@ impl<'tcx> Ty<'tcx> { /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). #[inline] pub fn is_any_ptr(self) -> bool { - self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr() + self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr() } #[inline] diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index b090bd9d807..f05b873432d 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -302,8 +302,8 @@ impl<'tcx> InternalSubsts<'tcx> { } /// Creates an `InternalSubsts` that maps each generic parameter to itself. - pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { - Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param)) + pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: impl Into<DefId>) -> SubstsRef<'tcx> { + Self::for_item(tcx, def_id.into(), |param, _| tcx.mk_param_from_def(param)) } /// Creates an `InternalSubsts` for generic parameter definitions, diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index bf2b121f704..6747da7abd3 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -153,12 +153,7 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, ) -> impl Iterator<Item = DefId> + 'tcx { let impls = self.trait_impls_of(trait_def_id); - if let Some(simp) = fast_reject::simplify_type( - self, - self_ty, - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { return impls.iter().copied(); } @@ -191,13 +186,17 @@ impl<'tcx> TyCtxt<'tcx> { } } + // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using + // `TreatParams::AsCandidateKey` while actually adding them. + let treat_params = match treat_projections { + TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup, + TreatProjections::ForLookup => TreatParams::ForLookup, + }; // This way, when searching for some impl for `T: Trait`, we do not look at any impls // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on. - if let Some(simp) = - fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup, treat_projections) - { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { if let result @ Some(_) = f(impl_def_id) { @@ -258,12 +257,9 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait continue; } - if let Some(simplified_self_ty) = fast_reject::simplify_type( - tcx, - impl_self_ty, - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(simplified_self_ty) = + fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey) + { impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); } else { impls.blanket_impls.push(impl_def_id); diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 586958247fc..2b0fb4dc2b7 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -8,10 +8,9 @@ use crate::{ }, }; use rustc_data_structures::{ - fx::FxHashMap, + fx::{FxHashMap, FxIndexMap}, sync::Lrc, unord::{UnordItems, UnordSet}, - vec_map::VecMap, }; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -155,7 +154,7 @@ pub struct TypeckResults<'tcx> { /// by this function. We also store the /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, /// even if they are only set in dead code (which doesn't show up in MIR). - pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index dc585f438f4..dcd9743196e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -15,7 +15,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; @@ -1439,8 +1439,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( } /// Determines whether an item is annotated with `doc(hidden)`. -fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - assert!(def_id.is_local()); +fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { tcx.get_attrs(def_id, sym::doc) .filter_map(|attr| attr.meta_item_list()) .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) @@ -1454,7 +1453,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } /// Determines whether an item is an intrinsic by Abi. -pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { +pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) } diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 5e77f2dc126..bf58b3090fb 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -137,6 +137,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> { parse_by_kind!(self, expr_id, expr, "rvalue", @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant), + @call("mir_cast_transmute", args) => { + let source = self.parse_operand(args[0])?; + Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty)) + }, @call("mir_checked", args) => { parse_by_kind!(self, args[0], _, "binary op", ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp( @@ -166,6 +170,28 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { let cast_kind = mir_cast_kind(source_ty, expr.ty); Ok(Rvalue::Cast(cast_kind, source, expr.ty)) }, + ExprKind::Tuple { fields } => Ok( + Rvalue::Aggregate( + Box::new(AggregateKind::Tuple), + fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()? + ) + ), + ExprKind::Array { fields } => { + let elem_ty = expr.ty.builtin_index().expect("ty must be an array"); + Ok(Rvalue::Aggregate( + Box::new(AggregateKind::Array(elem_ty)), + fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()? + )) + }, + ExprKind::Adt(box AdtExpr{ adt_def, variant_index, substs, fields, .. }) => { + let is_union = adt_def.is_union(); + let active_field_index = is_union.then(|| fields[0].name.index()); + + Ok(Rvalue::Aggregate( + Box::new(AggregateKind::Adt(adt_def.did(), *variant_index, substs, None, active_field_index)), + fields.iter().map(|f| self.parse_operand(f.expr)).collect::<Result<_, _>>()? + )) + }, _ => self.parse_operand(expr_id).map(Rvalue::Use), ) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index ff3198847df..6941da331fc 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -20,7 +20,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { let local_scope = self.local_scope(); - self.as_operand(block, Some(local_scope), expr, None, NeedsTemporary::Maybe) + self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -102,7 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut block: BasicBlock, scope: Option<region::Scope>, expr: &Expr<'tcx>, - local_info: Option<Box<LocalInfo<'tcx>>>, + local_info: LocalInfo<'tcx>, needs_temporary: NeedsTemporary, ) -> BlockAnd<Operand<'tcx>> { let this = self; @@ -124,8 +124,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Category::Constant | Category::Place | Category::Rvalue(..) => { let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut)); - if this.local_decls[operand].local_info.is_none() { - this.local_decls[operand].local_info = local_info; + // Overwrite temp local info if we have something more interesting to record. + if !matches!(local_info, LocalInfo::Boring) { + let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local(); + if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info { + **decl_info = local_info; + } } block.and(Operand::Move(Place::from(operand))) } @@ -178,6 +182,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - this.as_operand(block, scope, expr, None, NeedsTemporary::Maybe) + this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe) } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 259e0f8f75c..3b775f590a4 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -64,7 +64,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[value], - None, + LocalInfo::Boring, NeedsTemporary::No ) ); @@ -73,19 +73,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Binary { op, lhs, rhs } => { let lhs = unpack!( - block = - this.as_operand(block, scope, &this.thir[lhs], None, NeedsTemporary::Maybe) + block = this.as_operand( + block, + scope, + &this.thir[lhs], + LocalInfo::Boring, + NeedsTemporary::Maybe + ) ); let rhs = unpack!( - block = - this.as_operand(block, scope, &this.thir[rhs], None, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[rhs], + LocalInfo::Boring, + NeedsTemporary::No + ) ); this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs) } ExprKind::Unary { op, arg } => { let arg = unpack!( - block = - this.as_operand(block, scope, &this.thir[arg], None, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[arg], + LocalInfo::Boring, + NeedsTemporary::No + ) ); // Check for -MIN on signed integers if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() { @@ -260,7 +275,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { let ty = source.ty; let source = unpack!( - block = this.as_operand(block, scope, source, None, NeedsTemporary::No) + block = this.as_operand(block, scope, source, LocalInfo::Boring, NeedsTemporary::No) ); (source, ty) }; @@ -272,8 +287,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Pointer { cast, source } => { let source = unpack!( - block = - this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[source], + LocalInfo::Boring, + NeedsTemporary::No + ) ); block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) } @@ -315,7 +335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[f], - None, + LocalInfo::Boring, NeedsTemporary::Maybe ) ) @@ -336,7 +356,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[f], - None, + LocalInfo::Boring, NeedsTemporary::Maybe ) ) @@ -424,7 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, upvar, - None, + LocalInfo::Boring, NeedsTemporary::Maybe ) ) @@ -502,8 +522,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Category::of(&expr.kind), Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant) )); - let operand = - unpack!(block = this.as_operand(block, scope, expr, None, NeedsTemporary::No)); + let operand = unpack!( + block = + this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No) + ); block.and(Rvalue::Use(operand)) } } @@ -544,41 +566,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Use(Operand::Move(val)) } BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => { - // Consider that the shift overflows if `rhs < 0` or `rhs >= bits`. - // This can be encoded as a single operation as `(rhs & -bits) != 0`. - let (size, _) = ty.int_size_and_signed(self.tcx); - let bits = size.bits(); - debug_assert!(bits.is_power_of_two()); - let mask = !((bits - 1) as u128); - + // For an unsigned RHS, the shift is in-range for `rhs < bits`. + // For a signed RHS, `IntToInt` cast to the equivalent unsigned + // type and do that same comparison. Because the type is the + // same size, there's no negative shift amount that ends up + // overlapping with valid ones, thus it catches negatives too. + let (lhs_size, _) = ty.int_size_and_signed(self.tcx); let rhs_ty = rhs.ty(&self.local_decls, self.tcx); let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx); - let mask = Operand::const_from_scalar( + + let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() { + ty::Uint(_) => (rhs.to_copy(), rhs_ty), + ty::Int(int_width) => { + let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned()); + let rhs_temp = self.temp(uint_ty, span); + self.cfg.push_assign( + block, + source_info, + rhs_temp, + Rvalue::Cast(CastKind::IntToInt, rhs.to_copy(), uint_ty), + ); + (Operand::Move(rhs_temp), uint_ty) + } + _ => unreachable!("only integers are shiftable"), + }; + + // This can't overflow because the largest shiftable types are 128-bit, + // which fits in `u8`, the smallest possible `unsigned_ty`. + // (And `from_uint` will `bug!` if that's ever no longer true.) + let lhs_bits = Operand::const_from_scalar( self.tcx, - rhs_ty, - Scalar::from_uint(rhs_size.truncate(mask), rhs_size), + unsigned_ty, + Scalar::from_uint(lhs_size.bits(), rhs_size), span, ); - let outer_bits = self.temp(rhs_ty, span); - self.cfg.push_assign( - block, - source_info, - outer_bits, - Rvalue::BinaryOp(BinOp::BitAnd, Box::new((rhs.to_copy(), mask))), - ); - - let overflows = self.temp(bool_ty, span); - let zero = self.zero_literal(span, rhs_ty); + let inbounds = self.temp(bool_ty, span); self.cfg.push_assign( block, source_info, - overflows, - Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Move(outer_bits), zero))), + inbounds, + Rvalue::BinaryOp(BinOp::Lt, Box::new((unsigned_rhs, lhs_bits))), ); let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy()); - block = self.assert(block, Operand::Move(overflows), false, overflow_err, span); + block = self.assert(block, Operand::Move(inbounds), true, overflow_err, span); Rvalue::BinaryOp(op, Box::new((lhs, rhs))) } BinOp::Div | BinOp::Rem if ty.is_integral() => { @@ -662,8 +694,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Repeating a const does nothing } else { // For a non-const, we may need to generate an appropriate `Drop` - let value_operand = - unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No)); + let value_operand = unpack!( + block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No) + ); if let Operand::Move(to_drop) = value_operand { let success = this.cfg.start_new_block(); this.cfg.terminate( diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 3d3cf75559e..c8910c272b1 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -49,29 +49,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context); - // Find out whether this temp is being created within the - // tail expression of a block whose result is ignored. - if let Some(tail_info) = this.block_context.currently_in_block_tail() { - local_decl = local_decl.block_tail(tail_info); - } - match expr.kind { + let local_info = match expr.kind { ExprKind::StaticRef { def_id, .. } => { assert!(!this.tcx.is_thread_local_static(def_id)); local_decl.internal = true; - local_decl.local_info = - Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: false })); + LocalInfo::StaticRef { def_id, is_thread_local: false } } ExprKind::ThreadLocalRef(def_id) => { assert!(this.tcx.is_thread_local_static(def_id)); local_decl.internal = true; - local_decl.local_info = - Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: true })); + LocalInfo::StaticRef { def_id, is_thread_local: true } } ExprKind::NamedConst { def_id, .. } | ExprKind::ConstParam { def_id, .. } => { - local_decl.local_info = Some(Box::new(LocalInfo::ConstRef { def_id })); + LocalInfo::ConstRef { def_id } } - _ => {} - } + // Find out whether this temp is being created within the + // tail expression of a block whose result is ignored. + _ if let Some(tail_info) = this.block_context.currently_in_block_tail() => { + LocalInfo::BlockTailTemp(tail_info) + } + _ => LocalInfo::Boring, + }; + **local_decl.local_info.as_mut().assert_crate_local() = local_info; this.local_decls.push(local_decl) }; let temp_place = Place::from(temp); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index dac9bf0a883..ebe8ea25ad3 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -328,7 +328,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fields_map: FxHashMap<_, _> = fields .into_iter() .map(|f| { - let local_info = Box::new(LocalInfo::AggregateTemp); ( f.name, unpack!( @@ -336,7 +335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Some(scope), &this.thir[f.expr], - Some(local_info), + LocalInfo::AggregateTemp, NeedsTemporary::Maybe, ) ), @@ -526,7 +525,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Some(scope), &this.thir[value], - None, + LocalInfo::Boring, NeedsTemporary::No ) ); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 3fb8a6db2d2..2d52102db2c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -607,9 +607,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // }; // ``` if let Some(place) = initializer.try_to_place(self) { - let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + let LocalInfo::User(BindingForm::Var( VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, - )))) = self.local_decls[local].local_info else { + )) = **self.local_decls[local].local_info.as_mut().assert_crate_local() else { bug!("Let binding to non-user variable.") }; *match_place = Some(place); @@ -1754,7 +1754,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); fake_borrow_temp.internal = self.local_decls[matched_place.local].internal; - fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow)); + fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow)); let fake_borrow_temp = self.local_decls.push(fake_borrow_temp); (matched_place, fake_borrow_temp) @@ -2224,8 +2224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) }, source_info, internal: false, - is_block_tail: None, - local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var( VarBindingForm { binding_mode, // hypothetically, `visit_primary_bindings` could try to unzip @@ -2236,7 +2235,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_match_place, pat_span, }, - ))))), + )))), }; let for_arm_body = self.local_decls.push(local); self.var_debug_info.push(VarDebugInfo { @@ -2253,10 +2252,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty: None, source_info, internal: false, - is_block_tail: None, - local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set( + local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User( BindingForm::RefForGuard, - )))), + ))), }); self.var_debug_info.push(VarDebugInfo { name, diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index baeb2718cae..90d78658f96 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -5,7 +5,7 @@ use crate::build::Builder; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -66,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.tcx; let ty = place.ty(&self.local_decls, tcx).ty; - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) { + if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) { Operand::Move(place) } else { Operand::Copy(place) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 70d5fc2d958..1923e10ddb5 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -3,6 +3,7 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_errors::ErrorGuaranteed; @@ -680,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on // the settings for the crate they are codegened in. - let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks); + let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks); // Respect -C overflow-checks. check_overflow |= tcx.sess.overflow_checks(); // Constants always need overflow checks. @@ -876,21 +877,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { self.local_decls[local].mutability = mutability; self.local_decls[local].source_info.scope = self.source_scope; - self.local_decls[local].local_info = if let Some(kind) = param.self_kind { - Some(Box::new(LocalInfo::User(ClearCrossCrate::Set( - BindingForm::ImplicitSelf(kind), - )))) - } else { - let binding_mode = ty::BindingMode::BindByValue(mutability); - Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { + **self.local_decls[local].local_info.as_mut().assert_crate_local() = + if let Some(kind) = param.self_kind { + LocalInfo::User(BindingForm::ImplicitSelf(kind)) + } else { + let binding_mode = ty::BindingMode::BindByValue(mutability); + LocalInfo::User(BindingForm::Var(VarBindingForm { binding_mode, opt_ty_info: param.ty_span, opt_match_place: Some((None, span)), pat_span: span, - }, - ))))) - }; + })) + }; self.var_indices.insert(var, LocalsForNode::One(local)); } _ => { diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index f6db329fd7c..8937b78fe34 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -18,7 +18,7 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let trait_substs = match tcx.trait_of_item(def_id.to_def_id()) { Some(trait_def_id) => { let trait_substs_count = tcx.generics_of(trait_def_id).count(); - &InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count] + &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count] } _ => &[], }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 9086412c09a..6fd9b9dbb57 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -185,7 +185,7 @@ impl<'tcx> Cx<'tcx> { if self.typeck_results().is_coercion_cast(source.hir_id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: self.mirror_expr(source) } - } else if self.typeck_results().expr_ty(source).is_region_ptr() { + } else if self.typeck_results().expr_ty(source).is_ref() { // Special cased so that we can type check that the element // type of the source matches the pointed to type of the // destination. @@ -780,7 +780,6 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::DropTemps(ref source) => { ExprKind::Use { source: self.mirror_expr(source) } } - hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) }, hir::ExprKind::Array(ref fields) => { ExprKind::Array { fields: self.mirror_exprs(fields) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ff88d001351..274c2f06137 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -1,14 +1,14 @@ use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::Obligation; use rustc_middle::mir::{self, Field}; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::Span; -use rustc_trait_selection::traits::predicate_for_trait_def; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; +use rustc_trait_selection::traits::{self, ObligationCause}; use std::cell::Cell; @@ -189,17 +189,15 @@ impl<'tcx> ConstToPat<'tcx> { // using `PartialEq::eq` in this scenario in the past.) let partial_eq_trait_id = self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); - let obligation: PredicateObligation<'_> = predicate_for_trait_def( + let partial_eq_obligation = Obligation::new( self.tcx(), + ObligationCause::dummy(), self.param_env, - ObligationCause::misc(self.span, self.id.owner.def_id), - partial_eq_trait_id, - 0, - [ty, ty], + self.tcx().mk_trait_ref(partial_eq_trait_id, [ty, ty]), ); - // FIXME: should this call a `predicate_must_hold` variant instead? - let has_impl = self.infcx.predicate_may_hold(&obligation); + // FIXME: should this call a `predicate_must_hold` variant instead? + let has_impl = self.infcx.predicate_may_hold(&partial_eq_obligation); // Note: To fix rust-lang/rust#65466, we could just remove this type // walk hack for function pointers, and unconditionally error diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index bd12087629c..486275570bd 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -655,26 +655,20 @@ where /// /// ```text /// loop-block: - /// can_go = cur == length_or_end + /// can_go = cur == len /// if can_go then succ else drop-block /// drop-block: - /// if ptr_based { - /// ptr = cur - /// cur = cur.offset(1) - /// } else { - /// ptr = &raw mut P[cur] - /// cur = cur + 1 - /// } + /// ptr = &raw mut P[cur] + /// cur = cur + 1 /// drop(ptr) /// ``` fn drop_loop( &mut self, succ: BasicBlock, cur: Local, - length_or_end: Place<'tcx>, + len: Local, ety: Ty<'tcx>, unwind: Unwind, - ptr_based: bool, ) -> BasicBlock { let copy = |place: Place<'tcx>| Operand::Copy(place); let move_ = |place: Place<'tcx>| Operand::Move(place); @@ -683,22 +677,19 @@ where let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut }); let ptr = Place::from(self.new_temp(ptr_ty)); let can_go = Place::from(self.new_temp(tcx.types.bool)); - let one = self.constant_usize(1); - let (ptr_next, cur_next) = if ptr_based { - ( - Rvalue::Use(copy(cur.into())), - Rvalue::BinaryOp(BinOp::Offset, Box::new((move_(cur.into()), one))), - ) - } else { - ( - Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)), - Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), - ) - }; let drop_block = BasicBlockData { - statements: vec![self.assign(ptr, ptr_next), self.assign(Place::from(cur), cur_next)], + statements: vec![ + self.assign( + ptr, + Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)), + ), + self.assign( + cur.into(), + Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), + ), + ], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { source_info: self.source_info, @@ -711,10 +702,7 @@ where let loop_block = BasicBlockData { statements: vec![self.assign( can_go, - Rvalue::BinaryOp( - BinOp::Eq, - Box::new((copy(Place::from(cur)), copy(length_or_end))), - ), + Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))), )], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { @@ -738,13 +726,6 @@ where fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> BasicBlock { debug!("open_drop_for_array({:?}, {:?})", ety, opt_size); - - // if size_of::<ety>() == 0 { - // index_based_loop - // } else { - // ptr_based_loop - // } - let tcx = self.tcx(); if let Some(size) = opt_size { @@ -770,86 +751,36 @@ where } } - let move_ = |place: Place<'tcx>| Operand::Move(place); - let elem_size = Place::from(self.new_temp(tcx.types.usize)); - let len = Place::from(self.new_temp(tcx.types.usize)); - - let base_block = BasicBlockData { - statements: vec![ - self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), - self.assign(len, Rvalue::Len(self.place)), - ], - is_cleanup: self.unwind.is_cleanup(), - terminator: Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::SwitchInt { - discr: move_(elem_size), - targets: SwitchTargets::static_if( - 0, - self.drop_loop_pair(ety, false, len), - self.drop_loop_pair(ety, true, len), - ), - }, - }), - }; - self.elaborator.patch().new_block(base_block) + self.drop_loop_pair(ety) } /// Creates a pair of drop-loops of `place`, which drops its contents, even - /// in the case of 1 panic. If `ptr_based`, creates a pointer loop, - /// otherwise create an index loop. - fn drop_loop_pair( - &mut self, - ety: Ty<'tcx>, - ptr_based: bool, - length: Place<'tcx>, - ) -> BasicBlock { - debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based); + /// in the case of 1 panic. + fn drop_loop_pair(&mut self, ety: Ty<'tcx>) -> BasicBlock { + debug!("drop_loop_pair({:?})", ety); let tcx = self.tcx(); - let iter_ty = if ptr_based { tcx.mk_mut_ptr(ety) } else { tcx.types.usize }; + let len = self.new_temp(tcx.types.usize); + let cur = self.new_temp(tcx.types.usize); - let cur = self.new_temp(iter_ty); - let length_or_end = if ptr_based { Place::from(self.new_temp(iter_ty)) } else { length }; + let unwind = + self.unwind.map(|unwind| self.drop_loop(unwind, cur, len, ety, Unwind::InCleanup)); - let unwind = self.unwind.map(|unwind| { - self.drop_loop(unwind, cur, length_or_end, ety, Unwind::InCleanup, ptr_based) - }); + let loop_block = self.drop_loop(self.succ, cur, len, ety, unwind); - let loop_block = self.drop_loop(self.succ, cur, length_or_end, ety, unwind, ptr_based); - - let cur = Place::from(cur); - let drop_block_stmts = if ptr_based { - let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place)); - let tmp = Place::from(self.new_temp(tmp_ty)); - // tmp = &raw mut P; - // cur = tmp as *mut T; - // end = Offset(cur, len); - let mir_cast_kind = ty::cast::mir_cast_kind(iter_ty, tmp_ty); - vec![ - self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)), - self.assign(cur, Rvalue::Cast(mir_cast_kind, Operand::Move(tmp), iter_ty)), - self.assign( - length_or_end, - Rvalue::BinaryOp( - BinOp::Offset, - Box::new((Operand::Copy(cur), Operand::Move(length))), - ), - ), - ] - } else { - // cur = 0 (length already pushed) - let zero = self.constant_usize(0); - vec![self.assign(cur, Rvalue::Use(zero))] - }; - let drop_block = self.elaborator.patch().new_block(BasicBlockData { - statements: drop_block_stmts, + let zero = self.constant_usize(0); + let block = BasicBlockData { + statements: vec![ + self.assign(len.into(), Rvalue::Len(self.place)), + self.assign(cur.into(), Rvalue::Use(zero)), + ], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { source_info: self.source_info, kind: TerminatorKind::Goto { target: loop_block }, }), - }); + }; + let drop_block = self.elaborator.patch().new_block(block); // FIXME(#34708): handle partially-dropped array/slice elements. let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); self.drop_flag_test_block(reset_block, self.succ, unwind) diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 536745d2cfe..3d32c586554 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -24,7 +24,7 @@ struct ConstMutationChecker<'a, 'tcx> { impl<'tcx> ConstMutationChecker<'_, 'tcx> { fn is_const_item(&self, local: Local) -> Option<DefId> { - if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info { + if let LocalInfo::ConstRef { def_id } = *self.body.local_decls[local].local_info() { Some(def_id) } else { None diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index a8ec568eb0d..c4d058e8ecb 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -182,7 +182,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // If the projection root is an artificial local that we introduced when // desugaring `static`, give a more specific error message // (avoid the general "raw pointer" clause below, that would only be confusing). - if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { + if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() { if self.tcx.is_mutable_static(def_id) { self.require_unsafe( UnsafetyViolationKind::General, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index de7b8c63fc8..c1cf6ee0f9e 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -4,6 +4,7 @@ use either::Right; use rustc_const_eval::const_eval::CheckAlignment; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; @@ -151,12 +152,17 @@ impl<'tcx> MirPass<'tcx> for ConstProp { pub struct ConstPropMachine<'mir, 'tcx> { /// The virtual call stack. stack: Vec<Frame<'mir, 'tcx>>, + pub written_only_inside_own_block_locals: FxHashSet<Local>, pub can_const_prop: IndexVec<Local, ConstPropMode>, } impl ConstPropMachine<'_, '_> { pub fn new(can_const_prop: IndexVec<Local, ConstPropMode>) -> Self { - Self { stack: Vec::new(), can_const_prop } + Self { + stack: Vec::new(), + written_only_inside_own_block_locals: Default::default(), + can_const_prop, + } } } @@ -174,7 +180,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { false // for now, we don't enforce validity } fn alignment_check_failed( @@ -249,7 +255,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> "tried to write to a local that is marked as not propagatable" ) } - ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {} + ConstPropMode::OnlyInsideOwnBlock => { + ecx.machine.written_only_inside_own_block_locals.insert(local); + } + ConstPropMode::FullConstProp => {} } ecx.machine.stack[frame].locals[local].access_mut() } @@ -416,6 +425,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { ecx.frame_mut().locals[local].value = LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)); + ecx.machine.written_only_inside_own_block_locals.remove(&local); } /// Returns the value, if any, of evaluating `c`. @@ -494,6 +504,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } + // Do not try creating references, nor any types with potentially-complex + // invariants. This avoids an issue where checking validity would do a + // bunch of work generating a nice message about the invariant violation, + // only to not show it to anyone (since this isn't the lint). + Rvalue::Cast(CastKind::Transmute, op, dst_ty) if !dst_ty.is_primitive() => { + trace!("skipping Transmute of {:?} to {:?}", op, dst_ty); + + return None; + } // There's no other checking to do at this time. Rvalue::Aggregate(..) @@ -693,7 +712,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - fn ensure_not_propagated(&mut self, local: Local) { + fn ensure_not_propagated(&self, local: Local) { if cfg!(debug_assertions) { assert!( self.get_const(local.into()).is_none() @@ -963,17 +982,31 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { // We remove all Locals which are restricted in propagation to their containing blocks and // which were modified in the current block. // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. - let can_const_prop = std::mem::take(&mut self.ecx.machine.can_const_prop); - for (local, &mode) in can_const_prop.iter_enumerated() { - match mode { - ConstPropMode::FullConstProp => {} - ConstPropMode::NoPropagation => self.ensure_not_propagated(local), - ConstPropMode::OnlyInsideOwnBlock => { - Self::remove_const(&mut self.ecx, local); - self.ensure_not_propagated(local); + let mut written_only_inside_own_block_locals = + std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); + + // This loop can get very hot for some bodies: it check each local in each bb. + // To avoid this quadratic behaviour, we only clear the locals that were modified inside + // the current block. + for local in written_only_inside_own_block_locals.drain() { + debug_assert_eq!( + self.ecx.machine.can_const_prop[local], + ConstPropMode::OnlyInsideOwnBlock + ); + Self::remove_const(&mut self.ecx, local); + } + self.ecx.machine.written_only_inside_own_block_locals = + written_only_inside_own_block_locals; + + if cfg!(debug_assertions) { + for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { + match mode { + ConstPropMode::FullConstProp => {} + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { + self.ensure_not_propagated(local); + } } } } - self.ecx.machine.can_const_prop = can_const_prop; } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 68e50070e56..45bd98f39d2 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -247,6 +247,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { ecx.frame_mut().locals[local].value = LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)); + ecx.machine.written_only_inside_own_block_locals.remove(&local); } fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> { @@ -484,7 +485,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Some(()) } - fn ensure_not_propagated(&mut self, local: Local) { + fn ensure_not_propagated(&self, local: Local) { if cfg!(debug_assertions) { assert!( self.get_const(local.into()).is_none() @@ -691,17 +692,31 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { // We remove all Locals which are restricted in propagation to their containing blocks and // which were modified in the current block. // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. - let can_const_prop = std::mem::take(&mut self.ecx.machine.can_const_prop); - for (local, &mode) in can_const_prop.iter_enumerated() { - match mode { - ConstPropMode::FullConstProp => {} - ConstPropMode::NoPropagation => self.ensure_not_propagated(local), - ConstPropMode::OnlyInsideOwnBlock => { - Self::remove_const(&mut self.ecx, local); - self.ensure_not_propagated(local); + let mut written_only_inside_own_block_locals = + std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); + + // This loop can get very hot for some bodies: it check each local in each bb. + // To avoid this quadratic behaviour, we only clear the locals that were modified inside + // the current block. + for local in written_only_inside_own_block_locals.drain() { + debug_assert_eq!( + self.ecx.machine.can_const_prop[local], + ConstPropMode::OnlyInsideOwnBlock + ); + Self::remove_const(&mut self.ecx, local); + } + self.ecx.machine.written_only_inside_own_block_locals = + written_only_inside_own_block_locals; + + if cfg!(debug_assertions) { + for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { + match mode { + ConstPropMode::FullConstProp => {} + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { + self.ensure_not_propagated(local); + } } } } - self.ecx.machine.can_const_prop = can_const_prop; } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 49ded10ba1f..a7218a4f250 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_middle::mir::visit::{MutVisitor, Visitor}; use rustc_middle::mir::*; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace}; use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects}; @@ -548,7 +549,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi unimplemented!() } - fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { unimplemented!() } fn alignment_check_failed( diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index 89ca04a1582..e5c3fa5646a 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -5,7 +5,7 @@ //! purposes on a best-effort basis. We compute them here and store them into the crate metadata so //! dependent crates can use them. -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE}; @@ -149,7 +149,10 @@ fn type_will_always_be_passed_directly(ty: Ty<'_>) -> bool { /// body of the function instead of just the signature. These can be useful for optimization /// purposes on a best-effort basis. We compute them here and store them into the crate metadata so /// dependent crates can use them. -pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [DeducedParamAttrs] { +pub fn deduced_param_attrs<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> &'tcx [DeducedParamAttrs] { // This computation is unfortunately rather expensive, so don't do it unless we're optimizing. // Also skip it in incremental mode. if tcx.sess.opts.optimize == OptLevel::No || tcx.sess.opts.incremental.is_some() { @@ -182,10 +185,6 @@ pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [Ded return &[]; } - // Deduced attributes for other crates should be read from the metadata instead of via this - // function. - debug_assert!(def_id.is_local()); - // Grab the optimized MIR. Analyze it to determine which arguments have been mutated. let body: &Body<'tcx> = tcx.optimized_mir(def_id); let mut deduce_read_only = DeduceReadOnly::new(body.arg_count); diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index 7508df92df1..b8a5b92be4a 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -40,7 +40,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { let temp = self.patcher.new_internal_with_info( ty, self.local_decls[p_ref.local].source_info.span, - Some(Box::new(LocalInfo::DerefTemp)), + LocalInfo::DerefTemp, ); // We are adding current p_ref's projections to our diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 7344ec793ea..35e7efed87a 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -788,7 +788,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> { fn is_local_required(local: Local, body: &Body<'_>) -> bool { match body.local_kind(local) { LocalKind::Arg | LocalKind::ReturnPointer => true, - LocalKind::Var | LocalKind::Temp => false, + LocalKind::Temp => false, } } diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index e6546911a2d..c9b24adba0c 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -1,5 +1,6 @@ -use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_middle::mir::*; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::layout; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; @@ -121,9 +122,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { tainted } -fn required_panic_strategy(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<PanicStrategy> { - assert_eq!(cnum, LOCAL_CRATE); - +fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrategy> { if tcx.is_panic_runtime(LOCAL_CRATE) { return Some(tcx.sess.panic_strategy()); } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index b7f1cdfc7f2..8a6360114dc 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -70,7 +70,7 @@ use rustc_mir_dataflow::impls::{ }; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{self, Analysis}; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::VariantIdx; @@ -924,13 +924,19 @@ fn compute_layout<'tcx>( debug!(?decl); let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir { + // Do not `assert_crate_local` here, as post-borrowck cleanup may have already cleared + // the information. This is alright, since `ignore_for_traits` is only relevant when + // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer + // default. match decl.local_info { // Do not include raw pointers created from accessing `static` items, as those could // well be re-created by another access to the same static. - Some(box LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local, + ClearCrossCrate::Set(box LocalInfo::StaticRef { is_thread_local, .. }) => { + !is_thread_local + } // Fake borrows are only read by fake reads, so do not have any reality in // post-analysis MIR. - Some(box LocalInfo::FakeBorrow) => true, + ClearCrossCrate::Set(box LocalInfo::FakeBorrow) => true, _ => false, } } else { @@ -1380,10 +1386,9 @@ fn create_cases<'tcx>( #[instrument(level = "debug", skip(tcx), ret)] pub(crate) fn mir_generator_witnesses<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + def_id: LocalDefId, ) -> GeneratorLayout<'tcx> { assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); - let def_id = def_id.expect_local(); let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id)); let body = body.borrow(); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b2c477c84d2..3a515fe8323 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -29,9 +29,9 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{ - traversal, AnalysisPhase, Body, ConstQualifs, Constant, LocalDecl, MirPass, MirPhase, Operand, - Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, - TerminatorKind, + traversal, AnalysisPhase, Body, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, MirPass, + MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, + Statement, StatementKind, TerminatorKind, }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; @@ -112,7 +112,6 @@ pub fn provide(providers: &mut Providers) { mir_keys, mir_const, mir_const_qualif: |tcx, def_id| { - let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.mir_const_qualif_const_arg(def) } else { @@ -133,7 +132,6 @@ pub fn provide(providers: &mut Providers) { mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable, mir_inliner_callees: inline::cycle::mir_inliner_callees, promoted_mir: |tcx, def_id| { - let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.promoted_mir_of_const_arg(def) } else { @@ -206,8 +204,7 @@ fn remap_mir_for_const_eval_select<'tcx>( body } -fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let def_id = def_id.expect_local(); +fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { tcx.mir_keys(()).contains(&def_id) } @@ -350,12 +347,11 @@ fn mir_promoted( } /// Compute the MIR that is used during CTFE (and thus has no optimizations run on it) -fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { - let did = def_id.expect_local(); - if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { +fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> { + if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.mir_for_ctfe_of_const_arg(def) } else { - tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did))) + tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(def_id))) } } @@ -532,6 +528,12 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")]; pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup))); + + // Clear this by anticipation. Optimizations and runtime MIR have no reason to look + // into this information, which is meant for borrowck diagnostics. + for decl in &mut body.local_decls { + decl.local_info = ClearCrossCrate::Clear; + } } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -593,8 +595,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } /// Optimize the MIR and prepare it for codegen. -fn optimized_mir(tcx: TyCtxt<'_>, did: DefId) -> &Body<'_> { - let did = did.expect_local(); +fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> { assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None); tcx.arena.alloc(inner_optimized_mir(tcx, did)) } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 5d7382305ae..6a7ceb8fef7 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_target::abi::VariantIdx; pub struct LowerIntrinsics; @@ -191,6 +192,61 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } } + sym::option_payload_ptr => { + if let (Some(target), Some(arg)) = (*target, args[0].place()) { + let ty::RawPtr(ty::TypeAndMut { ty: dest_ty, .. }) = + destination.ty(local_decls, tcx).ty.kind() + else { bug!(); }; + + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::AddressOf( + Mutability::Not, + arg.project_deeper( + &[ + PlaceElem::Deref, + PlaceElem::Downcast( + Some(sym::Some), + VariantIdx::from_u32(1), + ), + PlaceElem::Field(Field::from_u32(0), *dest_ty), + ], + tcx, + ), + ), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + sym::transmute => { + let dst_ty = destination.ty(local_decls, tcx).ty; + let Ok([arg]) = <[_; 1]>::try_from(std::mem::take(args)) else { + span_bug!( + terminator.source_info.span, + "Wrong number of arguments for transmute intrinsic", + ); + }; + + // Always emit the cast, even if we transmute to an uninhabited type, + // because that lets CTFE and codegen generate better error messages + // when such a transmute actually ends up reachable. + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::Cast(CastKind::Transmute, arg, dst_ty), + ))), + }); + + if let Some(target) = *target { + terminator.kind = TerminatorKind::Goto { target }; + } else { + terminator.kind = TerminatorKind::Unreachable; + } + } _ if intrinsic_name.as_str().starts_with("simd_shuffle") => { validate_simd_shuffle(tcx, args, terminator.source_info.span); } diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index 4291e81c78c..b6e73eaad50 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -102,7 +102,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> { mir::LocalKind::Arg => return None, mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"), - mir::LocalKind::Var | mir::LocalKind::Temp => {} + mir::LocalKind::Temp => {} } // If multiple different locals are copied to the return place. We can't pick a diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 1becfddb23b..1f37f03cff1 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -1,7 +1,9 @@ -//! Removes assignments to ZST places. +//! Removes operations on ZST places, and convert ZST operands to constants. use crate::MirPass; -use rustc_middle::mir::{Body, StatementKind}; +use rustc_middle::mir::interpret::ConstValue; +use rustc_middle::mir::visit::*; +use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; pub struct RemoveZsts; @@ -16,38 +18,24 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts { if tcx.type_of(body.source.def_id()).subst_identity().is_generator() { return; } - let param_env = tcx.param_env(body.source.def_id()); - let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); let local_decls = &body.local_decls; - for block in basic_blocks { - for statement in block.statements.iter_mut() { - if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) = - statement.kind - { - let place_ty = place.ty(local_decls, tcx).ty; - if !maybe_zst(place_ty) { - continue; - } - let Ok(layout) = tcx.layout_of(param_env.and(place_ty)) else { - continue; - }; - if !layout.is_zst() { - continue; - } - if tcx.consider_optimizing(|| { - format!( - "RemoveZsts - Place: {:?} SourceInfo: {:?}", - place, statement.source_info - ) - }) { - statement.make_nop(); - } - } - } + let mut replacer = Replacer { tcx, param_env, local_decls }; + for var_debug_info in &mut body.var_debug_info { + replacer.visit_var_debug_info(var_debug_info); + } + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + replacer.visit_basic_block_data(bb, data); } } } +struct Replacer<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + local_decls: &'a LocalDecls<'tcx>, +} + /// A cheap, approximate check to avoid unnecessary `layout_of` calls. fn maybe_zst(ty: Ty<'_>) -> bool { match ty.kind() { @@ -63,3 +51,93 @@ fn maybe_zst(ty: Ty<'_>) -> bool { _ => false, } } + +impl<'tcx> Replacer<'_, 'tcx> { + fn known_to_be_zst(&self, ty: Ty<'tcx>) -> bool { + if !maybe_zst(ty) { + return false; + } + let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else { + return false; + }; + layout.is_zst() + } + + fn make_zst(&self, ty: Ty<'tcx>) -> Constant<'tcx> { + debug_assert!(self.known_to_be_zst(ty)); + Constant { + span: rustc_span::DUMMY_SP, + user_ty: None, + literal: ConstantKind::Val(ConstValue::ZeroSized, ty), + } + } +} + +impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) { + match var_debug_info.value { + VarDebugInfoContents::Const(_) => {} + VarDebugInfoContents::Place(place) => { + let place_ty = place.ty(self.local_decls, self.tcx).ty; + if self.known_to_be_zst(place_ty) { + var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty)) + } + } + VarDebugInfoContents::Composite { ty, fragments: _ } => { + if self.known_to_be_zst(ty) { + var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(ty)) + } + } + } + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { + if let Operand::Constant(_) = operand { + return; + } + let op_ty = operand.ty(self.local_decls, self.tcx); + if self.known_to_be_zst(op_ty) + && self.tcx.consider_optimizing(|| { + format!("RemoveZsts - Operand: {:?} Location: {:?}", operand, loc) + }) + { + *operand = Operand::Constant(Box::new(self.make_zst(op_ty))) + } + } + + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, loc: Location) { + let place_for_ty = match statement.kind { + StatementKind::Assign(box (place, ref rvalue)) => { + rvalue.is_safe_to_remove().then_some(place) + } + StatementKind::Deinit(box place) + | StatementKind::SetDiscriminant { box place, variant_index: _ } + | StatementKind::AscribeUserType(box (place, _), _) + | StatementKind::Retag(_, box place) + | StatementKind::PlaceMention(box place) + | StatementKind::FakeRead(box (_, place)) => Some(place), + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + Some(local.into()) + } + StatementKind::Coverage(_) + | StatementKind::Intrinsic(_) + | StatementKind::Nop + | StatementKind::ConstEvalCounter => None, + }; + if let Some(place_for_ty) = place_for_ty + && let ty = place_for_ty.ty(self.local_decls, self.tcx).ty + && self.known_to_be_zst(ty) + && self.tcx.consider_optimizing(|| { + format!("RemoveZsts - Place: {:?} SourceInfo: {:?}", place_for_ty, statement.source_info) + }) + { + statement.make_nop(); + } else { + self.super_statement(statement, loc); + } + } +} diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index c39ada95a4e..96765c296e7 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -336,7 +336,7 @@ parse_expected_identifier_found_reserved_keyword = expected identifier, found re parse_expected_identifier_found_doc_comment = expected identifier, found doc comment parse_expected_identifier = expected identifier -parse_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier +parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier parse_sugg_remove_comma = remove this comma diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index af0c3026c66..a9d116012ae 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -888,12 +888,12 @@ pub(crate) struct InvalidMetaItem { #[derive(Subdiagnostic)] #[suggestion( - parse_sugg_escape_to_use_as_identifier, + parse_sugg_escape_identifier, style = "verbose", applicability = "maybe-incorrect", code = "r#" )] -pub(crate) struct SuggEscapeToUseAsIdentifier { +pub(crate) struct SuggEscapeIdentifier { #[primary_span] pub span: Span, pub ident_name: String, @@ -937,7 +937,7 @@ impl ExpectedIdentifierFound { pub(crate) struct ExpectedIdentifier { pub span: Span, pub token: Token, - pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>, + pub suggest_raw: Option<SuggEscapeIdentifier>, pub suggest_remove_comma: Option<SuggRemoveComma>, pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>, } @@ -986,7 +986,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { #[derive(Subdiagnostic)] #[help(parse_invalid_identifier_with_leading_number)] -pub(crate) struct HelpIdentifierStartsWithNumber; +pub(crate) struct HelpIdentifierStartsWithNumber { + #[primary_span] + pub num_span: Span, +} pub(crate) struct ExpectedSemi { pub span: Span, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5b12bcc1822..9544afd3d6d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -6,14 +6,14 @@ use super::{ use crate::errors::{ AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, - ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType, - DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, + DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, - StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma, + StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; @@ -38,7 +38,7 @@ use rustc_errors::{ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; +use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP}; use std::mem::take; use std::ops::{Deref, DerefMut}; use thin_vec::{thin_vec, ThinVec}; @@ -268,7 +268,21 @@ impl<'a> Parser<'a> { self.sess.source_map().span_to_snippet(span) } - pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + /// Emits an error with suggestions if an identifier was expected but not found. + /// + /// Returns a possibly recovered identifier. + pub(super) fn expected_ident_found( + &mut self, + recover: bool, + ) -> PResult<'a, (Ident, /* is_raw */ bool)> { + if let TokenKind::DocComment(..) = self.prev_token.kind { + return Err(DocCommentDoesNotDocumentAnything { + span: self.prev_token.span, + missing_comma: None, + } + .into_diagnostic(&self.sess.span_diagnostic)); + } + let valid_follow = &[ TokenKind::Eq, TokenKind::Colon, @@ -281,31 +295,51 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(Delimiter::Parenthesis), ]; - let suggest_raw = match self.token.ident() { - Some((ident, false)) - if ident.is_raw_guess() - && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => - { - Some(SuggEscapeToUseAsIdentifier { - span: ident.span.shrink_to_lo(), - // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, - // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` - ident_name: ident.name.to_string(), - }) - } - _ => None, - }; + let mut recovered_ident = None; + // we take this here so that the correct original token is retained in + // the diagnostic, regardless of eager recovery. + let bad_token = self.token.clone(); + + // suggest prepending a keyword in identifier position with `r#` + let suggest_raw = if let Some((ident, false)) = self.token.ident() + && ident.is_raw_guess() + && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) + { + recovered_ident = Some((ident, true)); + + // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, + // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` + let ident_name = ident.name.to_string(); + + Some(SuggEscapeIdentifier { + span: ident.span.shrink_to_lo(), + ident_name + }) + } else { None }; + + let suggest_remove_comma = + if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { + if recover { + self.bump(); + recovered_ident = self.ident_or_err(false).ok(); + }; - let suggest_remove_comma = (self.token == token::Comma - && self.look_ahead(1, |t| t.is_ident())) - .then_some(SuggRemoveComma { span: self.token.span }); + Some(SuggRemoveComma { span: bad_token.span }) + } else { + None + }; - let help_cannot_start_number = - self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber); + let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| { + let (invalid, valid) = self.token.span.split_at(len as u32); + + recovered_ident = Some((Ident::new(valid_portion, valid), false)); + + HelpIdentifierStartsWithNumber { num_span: invalid } + }); let err = ExpectedIdentifier { - span: self.token.span, - token: self.token.clone(), + span: bad_token.span, + token: bad_token, suggest_raw, suggest_remove_comma, help_cannot_start_number, @@ -314,6 +348,7 @@ impl<'a> Parser<'a> { // if the token we have is a `<` // it *might* be a misplaced generic + // FIXME: could we recover with this? if self.token == token::Lt { // all keywords that could have generic applied let valid_prev_keywords = @@ -364,18 +399,38 @@ impl<'a> Parser<'a> { } } - err + if let Some(recovered_ident) = recovered_ident && recover { + err.emit(); + Ok(recovered_ident) + } else { + Err(err) + } + } + + pub(super) fn expected_ident_found_err(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + self.expected_ident_found(false).unwrap_err() } /// Checks if the current token is a integer or float literal and looks like /// it could be a invalid identifier with digits at the start. - pub(super) fn is_lit_bad_ident(&mut self) -> bool { - matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. }) - // ensure that the integer literal is followed by a *invalid* - // suffix: this is how we know that it is a identifier with an - // invalid beginning. - if rustc_ast::MetaItemLit::from_token(&self.token).is_none() - ) + /// + /// Returns the number of characters (bytes) composing the invalid portion + /// of the identifier and the valid portion of the identifier. + pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> { + // ensure that the integer literal is followed by a *invalid* + // suffix: this is how we know that it is a identifier with an + // invalid beginning. + if let token::Literal(Lit { + kind: token::LitKind::Integer | token::LitKind::Float, + symbol, + suffix, + }) = self.token.kind + && rustc_ast::MetaItemLit::from_token(&self.token).is_none() + { + Some((symbol.as_str().len(), suffix.unwrap())) + } else { + None + } } pub(super) fn expected_one_of_not_found( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 296eb4d653c..8b69b3cb036 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1843,20 +1843,14 @@ impl<'a> Parser<'a> { &mut self, mk_lit_char: impl FnOnce(Symbol, Span) -> L, ) -> PResult<'a, L> { - if let token::Interpolated(inner) = &self.token.kind { - let expr = match inner.as_ref() { - token::NtExpr(expr) => Some(expr), - token::NtLiteral(expr) => Some(expr), - _ => None, - }; - if let Some(expr) = expr { - if matches!(expr.kind, ExprKind::Err) { - let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } - .into_diagnostic(&self.sess.span_diagnostic); - err.downgrade_to_delayed_bug(); - return Err(err); - } - } + if let token::Interpolated(nt) = &self.token.kind + && let token::NtExpr(e) | token::NtLiteral(e) = &**nt + && matches!(e.kind, ExprKind::Err) + { + let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } + .into_diagnostic(&self.sess.span_diagnostic); + err.downgrade_to_delayed_bug(); + return Err(err); } let token = self.token.clone(); let err = |self_: &Self| { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 85cc8ca02a9..ae8fe90e9d6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1181,7 +1181,7 @@ impl<'a> Parser<'a> { defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { let impl_span = self.token.span; - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { @@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> { /// Parses a field identifier. Specialized version of `parse_ident_common` /// for better diagnostics and suggestions. fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err()?; + let (ident, is_raw) = self.ident_or_err(true)?; if !is_raw && ident.is_reserved() { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { @@ -1776,7 +1776,7 @@ impl<'a> Parser<'a> { Err(err) => { err.cancel(); self.restore_snapshot(snapshot); - self.expected_ident_found() + self.expected_ident_found_err() } } } else if self.eat_keyword(kw::Struct) { @@ -1792,11 +1792,11 @@ impl<'a> Parser<'a> { Err(err) => { err.cancel(); self.restore_snapshot(snapshot); - self.expected_ident_found() + self.expected_ident_found_err() } } } else { - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); if self.eat_keyword_noexpect(kw::Let) && let removal_span = self.prev_token.span.until(self.token.span) && let Ok(ident) = self.parse_ident_common(false) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3251dd6d0c6..53c25a80c4b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -42,8 +42,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::errors::{ - DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, - NonStringAbiLiteral, + IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, }; bitflags::bitflags! { @@ -552,21 +551,11 @@ impl<'a> Parser<'a> { self.parse_ident_common(true) } - fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> { - self.token.ident().ok_or_else(|| match self.prev_token.kind { - TokenKind::DocComment(..) => DocCommentDoesNotDocumentAnything { - span: self.prev_token.span, - missing_comma: None, - } - .into_diagnostic(&self.sess.span_diagnostic), - _ => self.expected_ident_found(), - }) - } - fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err()?; + let (ident, is_raw) = self.ident_or_err(recover)?; + if !is_raw && ident.is_reserved() { - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); if recover { err.emit(); } else { @@ -577,6 +566,21 @@ impl<'a> Parser<'a> { Ok(ident) } + fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> { + let result = self.token.ident().ok_or_else(|| self.expected_ident_found(recover)); + + let (ident, is_raw) = match result { + Ok(ident) => ident, + Err(err) => match err { + // we recovered! + Ok(ident) => ident, + Err(err) => return Err(err), + }, + }; + + Ok((ident, is_raw)) + } + /// Checks if the next token is `tok`, and returns `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index fc9f1d1330a..2246002f5d3 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -348,10 +348,6 @@ impl<'a> Parser<'a> { lo = self.token.span; } - if self.is_lit_bad_ident() { - return Err(self.expected_ident_found()); - } - let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd { self.parse_pat_deref(expected)? } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { @@ -395,7 +391,13 @@ impl<'a> Parser<'a> { } else { PatKind::Lit(const_expr) } - } else if self.can_be_ident_pat() { + // Don't eagerly error on semantically invalid tokens when matching + // declarative macros, as the input to those doesn't have to be + // semantically valid. For attribute/derive proc macros this is not the + // case, so doing the recovery for them is fine. + } else if self.can_be_ident_pat() + || (self.is_lit_bad_ident().is_some() && self.may_recover()) + { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. @@ -594,7 +596,7 @@ impl<'a> Parser<'a> { // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. if let token::Interpolated(nt) = &self.token.kind { if let token::NtPat(_) = **nt { - self.expected_ident_found().emit(); + self.expected_ident_found_err().emit(); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8bed7888142..1c459edabb8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1907,7 +1907,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Fn => { for attr in attrs { - if self.tcx.sess.is_proc_macro_attr(attr) { + if attr.is_proc_macro_attr() { debug!("Is proc macro attr"); return true; } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 526b829bf67..30dd3e4d016 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -104,9 +104,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // If this crate is not using stability attributes, or this function is not claiming to be a // stable `const fn`, that is all that is required. - if !tcx.features().staged_api - || tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) - { + if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { return true; } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index ec1e1d0054b..75ce446e6b4 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -469,9 +469,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.has_attr(def_id.to_def_id(), sym::lang) + tcx.has_attr(def_id, sym::lang) // Stable attribute for #[lang = "panic_impl"] - || tcx.has_attr(def_id.to_def_id(), sym::panic_handler) + || tcx.has_attr(def_id, sym::panic_handler) } fn has_allow_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index aeacbaa67cb..9dd39a5c9fe 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -4,11 +4,9 @@ use hir::CRATE_HIR_ID; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::resolve_path; use rustc_hir as hir; -use rustc_hir::def_id::CrateNum; use rustc_hir::HirId; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::LOCAL_CRATE; +use rustc_middle::{query::LocalCrate, ty::query::Providers}; use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; use std::sync::Arc; @@ -69,9 +67,7 @@ fn check_for_debugger_visualizer( } /// Traverses and collects the debugger visualizers for a specific crate. -fn debugger_visualizers(tcx: TyCtxt<'_>, cnum: CrateNum) -> Vec<DebuggerVisualizerFile> { - assert_eq!(cnum, LOCAL_CRATE); - +fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> { // Initialize the collector. let mut debugger_visualizers = FxHashSet::default(); diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 110eb210df9..eb6ea673c85 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -12,9 +12,10 @@ use rustc_ast as ast; use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::OwnerId; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; use crate::errors::DuplicateDiagnosticItemInCrate; @@ -62,9 +63,7 @@ fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> { } /// Traverse and collect the diagnostic items in the current -fn diagnostic_items(tcx: TyCtxt<'_>, cnum: CrateNum) -> DiagnosticItems { - assert_eq!(cnum, LOCAL_CRATE); - +fn diagnostic_items(tcx: TyCtxt<'_>, _: LocalCrate) -> DiagnosticItems { // Initialize the collector. let mut diagnostic_items = DiagnosticItems::default(); diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index b7e6a11998b..f3e683f4b3a 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,3 +1,4 @@ +use rustc_ast::attr; use rustc_ast::entry::EntryPointType; use rustc_errors::error_code; use rustc_hir::def::DefKind; @@ -37,7 +38,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } // If the user wants no main function at all, then stop here. - if tcx.sess.contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) { + if attr::contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) { return None; } @@ -57,9 +58,9 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { // An equivalent optimization was not applied to the duplicated code in test_harness.rs. fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - if ctxt.tcx.sess.contains_name(attrs, sym::start) { + if attr::contains_name(attrs, sym::start) { EntryPointType::Start - } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) { + } else if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else { if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id()) @@ -78,7 +79,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span) + attr::find_by_name(attrs, sym).map(|attr| attr.span) } fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 3e0d53029ef..47e032758f2 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -300,7 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { record_variants!( (self, e, e.kind, Id::Node(e.hir_id), hir, Expr, ExprKind), [ - Box, ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, + ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf, Break, Continue, Ret, InlineAsm, Struct, Repeat, Yield, Err ] diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 047b9b525e8..5a1ae808e66 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -18,7 +18,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) { tcx.def_kind(id.owner_id), DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union ) { - for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) { + for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { dump_layout_of(tcx, id.owner_id.def_id, attr); } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index db9d0dcc300..a8471ce3b6f 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -146,7 +146,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: DefId) { // Don't run unused pass for #[derive()] let parent = tcx.local_parent(local_def_id); if let DefKind::Impl { .. } = tcx.def_kind(parent) - && tcx.has_attr(parent.to_def_id(), sym::automatically_derived) + && tcx.has_attr(parent, sym::automatically_derived) { return; } @@ -473,7 +473,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) @@ -1059,8 +1058,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&l, r_succ) } - hir::ExprKind::Box(ref e) - | hir::ExprKind::AddrOf(_, _, ref e) + hir::ExprKind::AddrOf(_, _, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) | hir::ExprKind::DropTemps(ref e) @@ -1425,7 +1423,6 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Closure { .. } | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err(_) => {} } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index c5b5cf7f5a9..c398467f03e 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -30,7 +30,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { continue; } - let naked = tcx.has_attr(def_id.to_def_id(), sym::naked); + let naked = tcx.has_attr(def_id, sym::naked); if !naked { continue; } @@ -59,7 +59,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { /// Check that the function isn't inlined. fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline); + let attrs = tcx.get_attrs(def_id, sym::inline); for attr in attrs { tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span }); } @@ -179,8 +179,7 @@ enum ItemKind { impl<'tcx> CheckInlineAssembly<'tcx> { fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { match expr.kind { - ExprKind::Box(..) - | ExprKind::ConstBlock(..) + ExprKind::ConstBlock(..) | ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::MethodCall(..) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index d5cc64a5402..6d0cfea00d1 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -691,14 +691,10 @@ pub(crate) fn provide(providers: &mut Providers) { check_mod_unstable_api_usage, stability_index, stability_implications: |tcx, _| tcx.stability().implications.clone(), - lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()), - lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()), - lookup_default_body_stability: |tcx, id| { - tcx.stability().local_default_body_stability(id.expect_local()) - }, - lookup_deprecation_entry: |tcx, id| { - tcx.stability().local_deprecation_entry(id.expect_local()) - }, + lookup_stability: |tcx, id| tcx.stability().local_stability(id), + lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), + lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id), + lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id), ..*providers }; } diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs index 8e75e969ae0..27e5cb9f0d0 100644 --- a/compiler/rustc_plugin_impl/src/load.rs +++ b/compiler/rustc_plugin_impl/src/load.rs @@ -3,7 +3,7 @@ use crate::errors::{LoadPluginError, MalformedPluginAttribute}; use crate::Registry; use libloading::Library; -use rustc_ast::Crate; +use rustc_ast::Attribute; use rustc_metadata::locator; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; @@ -20,11 +20,11 @@ type PluginRegistrarFn = fn(&mut Registry<'_>); pub fn load_plugins( sess: &Session, metadata_loader: &dyn MetadataLoader, - krate: &Crate, + attrs: &[Attribute], ) -> Vec<PluginRegistrarFn> { let mut plugins = Vec::new(); - for attr in &krate.attrs { + for attr in attrs { if !attr.has_name(sym::plugin) { continue; } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ef7c68c1a33..3be0160d561 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -132,7 +132,7 @@ where projection.trait_ref_and_own_substs(tcx) } else { // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys - let def_id = tcx.impl_trait_in_trait_parent(projection.def_id); + let def_id = tcx.impl_trait_in_trait_parent_fn(projection.def_id); let trait_generics = tcx.generics_of(def_id); ( tcx.mk_trait_ref(def_id, projection.substs.truncate_to(tcx, trait_generics)), @@ -180,7 +180,7 @@ where | ty::PredicateKind::ConstEquate(_, _) | ty::PredicateKind::TypeWellFormedFromEnv(_) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(_, _) => bug!("unexpected predicate: {:?}", predicate), + | ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate), } } @@ -920,7 +920,7 @@ pub struct TestReachabilityVisitor<'tcx, 'a> { impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { - if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) { + if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) { let mut error_msg = String::new(); let span = self.tcx.def_span(def_id.to_def_id()); if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) { @@ -2060,8 +2060,8 @@ pub fn provide(providers: &mut Providers) { }; } -fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility<DefId> { - local_visibility(tcx, def_id.expect_local()).to_def_id() +fn visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility<DefId> { + local_visibility(tcx, def_id).to_def_id() } fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 035bfe978f2..4cd94237061 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -20,7 +20,7 @@ extern crate rustc_middle; use rustc_data_structures::sync::AtomicU64; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::{self, DepKindStruct}; -use rustc_middle::query::Key; +use rustc_middle::query::AsLocalKey; use rustc_middle::ty::query::{ query_keys, query_provided, query_provided_to_value, query_storage, query_values, }; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index ca3c3997df0..9bba26cc8e8 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -274,19 +274,19 @@ macro_rules! hash_result { }; } -macro_rules! get_provider { - ([][$tcx:expr, $name:ident, $key:expr]) => {{ - $tcx.queries.local_providers.$name +macro_rules! call_provider { + ([][$qcx:expr, $name:ident, $key:expr]) => {{ + ($qcx.queries.local_providers.$name)($qcx.tcx, $key) }}; - ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{ - if $key.query_crate_is_local() { - $tcx.queries.local_providers.$name + ([(separate_provide_extern) $($rest:tt)*][$qcx:expr, $name:ident, $key:expr]) => {{ + if let Some(key) = $key.as_local_key() { + ($qcx.queries.local_providers.$name)($qcx.tcx, key) } else { - $tcx.queries.extern_providers.$name + ($qcx.queries.extern_providers.$name)($qcx.tcx, $key) } }}; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - get_provider!([$($modifiers)*][$($args)*]) + call_provider!([$($modifiers)*][$($args)*]) }; } @@ -516,7 +516,7 @@ macro_rules! define_queries { fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value { query_provided_to_value::$name( qcx.tcx, - get_provider!([$($modifiers)*][qcx, $name, key])(qcx.tcx, key) + call_provider!([$($modifiers)*][qcx, $name, key]) ) } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 8a9a1238606..3dbcc4d2e8a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -6,7 +6,6 @@ use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; -use rustc_data_structures::OnDrop; use rustc_index::vec::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use smallvec::{smallvec, SmallVec}; @@ -54,6 +53,11 @@ impl From<DepNodeIndex> for QueryInvocationId { } } +pub struct MarkFrame<'a> { + index: SerializedDepNodeIndex, + parent: Option<&'a MarkFrame<'a>>, +} + #[derive(PartialEq)] pub enum DepNodeColor { Red, @@ -710,32 +714,26 @@ impl<K: DepKind> DepGraphData<K> { let prev_index = self.previous.node_to_index_opt(dep_node)?; match self.colors.get(prev_index) { - Some(DepNodeColor::Green(dep_node_index)) => return Some((prev_index, dep_node_index)), - Some(DepNodeColor::Red) => return None, - None => {} + Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)), + Some(DepNodeColor::Red) => None, + None => { + // This DepNode and the corresponding query invocation existed + // in the previous compilation session too, so we can try to + // mark it as green by recursively marking all of its + // dependencies green. + self.try_mark_previous_green(qcx, prev_index, &dep_node, None) + .map(|dep_node_index| (prev_index, dep_node_index)) + } } - - let backtrace = backtrace_printer(qcx.dep_context().sess(), self, prev_index); - - // This DepNode and the corresponding query invocation existed - // in the previous compilation session too, so we can try to - // mark it as green by recursively marking all of its - // dependencies green. - let ret = self - .try_mark_previous_green(qcx, prev_index, &dep_node) - .map(|dep_node_index| (prev_index, dep_node_index)); - - // We succeeded, no backtrace. - backtrace.disable(); - return ret; } - #[instrument(skip(self, qcx, parent_dep_node_index), level = "debug")] + #[instrument(skip(self, qcx, parent_dep_node_index, frame), level = "debug")] fn try_mark_parent_green<Qcx: QueryContext<DepKind = K>>( &self, qcx: Qcx, parent_dep_node_index: SerializedDepNodeIndex, dep_node: &DepNode<K>, + frame: Option<&MarkFrame<'_>>, ) -> Option<()> { let dep_dep_node_color = self.colors.get(parent_dep_node_index); let dep_dep_node = &self.previous.index_to_node(parent_dep_node_index); @@ -767,7 +765,8 @@ impl<K: DepKind> DepGraphData<K> { dep_dep_node, dep_dep_node.hash, ); - let node_index = self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node); + let node_index = + self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node, frame); if node_index.is_some() { debug!("managed to MARK dependency {dep_dep_node:?} as green",); @@ -777,7 +776,7 @@ impl<K: DepKind> DepGraphData<K> { // We failed to mark it green, so we try to force the query. debug!("trying to force dependency {dep_dep_node:?}"); - if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node) { + if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node, frame) { // The DepNode could not be forced. debug!("dependency {dep_dep_node:?} could not be forced"); return None; @@ -816,13 +815,16 @@ impl<K: DepKind> DepGraphData<K> { } /// Try to mark a dep-node which existed in the previous compilation session as green. - #[instrument(skip(self, qcx, prev_dep_node_index), level = "debug")] + #[instrument(skip(self, qcx, prev_dep_node_index, frame), level = "debug")] fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>( &self, qcx: Qcx, prev_dep_node_index: SerializedDepNodeIndex, dep_node: &DepNode<K>, + frame: Option<&MarkFrame<'_>>, ) -> Option<DepNodeIndex> { + let frame = MarkFrame { index: prev_dep_node_index, parent: frame }; + #[cfg(not(parallel_compiler))] { debug_assert!(!self.dep_node_exists(dep_node)); @@ -837,10 +839,7 @@ impl<K: DepKind> DepGraphData<K> { let prev_deps = self.previous.edge_targets_from(prev_dep_node_index); for &dep_dep_node_index in prev_deps { - let backtrace = backtrace_printer(qcx.dep_context().sess(), self, dep_dep_node_index); - let success = self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node); - backtrace.disable(); - success?; + self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node, Some(&frame))?; } // If we got here without hitting a `return` that means that all @@ -970,6 +969,7 @@ impl<K: DepKind> DepGraph<K> { } pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex { + debug_assert!(self.data.is_none()); let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); DepNodeIndex::from_u32(index) } @@ -1414,25 +1414,25 @@ impl DepNodeColorMap { } } -fn backtrace_printer<'a, K: DepKind>( - sess: &'a rustc_session::Session, - graph: &'a DepGraphData<K>, - node: SerializedDepNodeIndex, -) -> OnDrop<impl Fn() + 'a> { - OnDrop( - #[inline(never)] - #[cold] - move || { - let node = graph.previous.index_to_node(node); - // Do not try to rely on DepNode's Debug implementation, since it may panic. - let diag = rustc_errors::Diagnostic::new( - rustc_errors::Level::FailureNote, - &format!( - "encountered while trying to mark dependency green: {:?}({})", - node.kind, node.hash - ), - ); - sess.diagnostic().force_print_diagnostic(diag); - }, - ) +#[inline(never)] +#[cold] +pub(crate) fn print_markframe_trace<K: DepKind>( + graph: &DepGraph<K>, + frame: Option<&MarkFrame<'_>>, +) { + let data = graph.data.as_ref().unwrap(); + + eprintln!("there was a panic while trying to force a dep node"); + eprintln!("try_mark_green dep node stack:"); + + let mut i = 0; + let mut current = frame; + while let Some(frame) = current { + let node = data.previous.index_to_node(frame.index); + eprintln!("#{i} {:?}", node); + current = frame.parent; + i += 1; + } + + eprintln!("end of try_mark_green dep node stack"); } diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 5a7b9ae2ab4..40e7131987f 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -17,8 +17,10 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_serialize::{opaque::FileEncoder, Encodable}; use rustc_session::Session; -use std::fmt; use std::hash::Hash; +use std::{fmt, panic}; + +use self::graph::{print_markframe_trace, MarkFrame}; pub trait DepContext: Copy { type DepKind: self::DepKind; @@ -53,11 +55,23 @@ pub trait DepContext: Copy { } /// Try to force a dep node to execute and see if it's green. - #[instrument(skip(self), level = "debug")] - fn try_force_from_dep_node(self, dep_node: DepNode<Self::DepKind>) -> bool { + #[inline] + #[instrument(skip(self, frame), level = "debug")] + fn try_force_from_dep_node( + self, + dep_node: DepNode<Self::DepKind>, + frame: Option<&MarkFrame<'_>>, + ) -> bool { let cb = self.dep_kind_info(dep_node.kind); if let Some(f) = cb.force_from_dep_node { - f(self, dep_node); + if let Err(value) = panic::catch_unwind(panic::AssertUnwindSafe(|| { + f(self, dep_node); + })) { + if !value.is::<rustc_errors::FatalErrorMarker>() { + print_markframe_trace(self.dep_graph(), frame); + } + panic::resume_unwind(value) + } true } else { false diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 005512cf53e..ba2f859ff0f 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -379,7 +379,11 @@ where match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, state_lock, span, key) { TryGetJob::NotYetStarted(job) => { - let (result, dep_node_index) = execute_job(query, qcx, key.clone(), dep_node, job.id); + let (result, dep_node_index) = match qcx.dep_context().dep_graph().data() { + None => execute_job_non_incr(query, qcx, key, job.id), + Some(data) => execute_job_incr(query, qcx, data, key, dep_node, job.id), + }; + let cache = query.query_cache(qcx); if query.feedable() { // We should not compute queries that also got a value via feeding. @@ -413,48 +417,55 @@ where } } +// Fast path for when incr. comp. is off. #[inline(always)] -fn execute_job<Q, Qcx>( +fn execute_job_non_incr<Q, Qcx>( query: Q, qcx: Qcx, key: Q::Key, - mut dep_node_opt: Option<DepNode<Qcx::DepKind>>, job_id: QueryJobId, ) -> (Q::Value, DepNodeIndex) where Q: QueryConfig<Qcx>, Qcx: QueryContext, { - let dep_graph = qcx.dep_context().dep_graph(); - let dep_graph_data = match dep_graph.data() { - // Fast path for when incr. comp. is off. - None => { - // Fingerprint the key, just to assert that it doesn't - // have anything we don't consider hashable - if cfg!(debug_assertions) { - let _ = key.to_fingerprint(*qcx.dep_context()); - } + debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled()); - let prof_timer = qcx.dep_context().profiler().query_provider(); - let result = - qcx.start_query(job_id, query.depth_limit(), None, || query.compute(qcx, key)); - let dep_node_index = dep_graph.next_virtual_depnode_index(); - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - // Similarly, fingerprint the result to assert that - // it doesn't have anything not considered hashable. - if cfg!(debug_assertions) && let Some(hash_result) = query.hash_result() - { - qcx.dep_context().with_stable_hashing_context(|mut hcx| { - hash_result(&mut hcx, &result); - }); - } + // Fingerprint the key, just to assert that it doesn't + // have anything we don't consider hashable + if cfg!(debug_assertions) { + let _ = key.to_fingerprint(*qcx.dep_context()); + } - return (result, dep_node_index); - } - Some(data) => data, - }; + let prof_timer = qcx.dep_context().profiler().query_provider(); + let result = qcx.start_query(job_id, query.depth_limit(), None, || query.compute(qcx, key)); + let dep_node_index = qcx.dep_context().dep_graph().next_virtual_depnode_index(); + prof_timer.finish_with_query_invocation_id(dep_node_index.into()); + + // Similarly, fingerprint the result to assert that + // it doesn't have anything not considered hashable. + if cfg!(debug_assertions) && let Some(hash_result) = query.hash_result() { + qcx.dep_context().with_stable_hashing_context(|mut hcx| { + hash_result(&mut hcx, &result); + }); + } + (result, dep_node_index) +} + +#[inline(always)] +fn execute_job_incr<Q, Qcx>( + query: Q, + qcx: Qcx, + dep_graph_data: &DepGraphData<Qcx::DepKind>, + key: Q::Key, + mut dep_node_opt: Option<DepNode<Qcx::DepKind>>, + job_id: QueryJobId, +) -> (Q::Value, DepNodeIndex) +where + Q: QueryConfig<Qcx>, + Qcx: QueryContext, +{ if !query.anon() && !query.eval_always() { // `to_dep_node` is expensive for some `DepKind`s. let dep_node = diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 362ef693c48..19ccb3a6484 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -27,7 +27,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_metadata::creader::LoadedMacro; use rustc_middle::metadata::ModChild; use rustc_middle::{bug, ty}; -use rustc_session::cstore::CrateStore; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -115,34 +114,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if !def_id.is_local() { - let def_kind = self.cstore().def_kind(def_id); - match def_kind { - DefKind::Mod | DefKind::Enum | DefKind::Trait => { - let def_key = self.cstore().def_key(def_id); - let parent = def_key.parent.map(|index| { - self.get_nearest_non_block_module(DefId { index, krate: def_id.krate }) - }); - let name = if let Some(cnum) = def_id.as_crate_root() { - self.cstore().crate_name(cnum) - } else { - def_key.disambiguated_data.data.get_opt_name().expect("module without name") - }; - - let expn_id = self.cstore().module_expansion_untracked(def_id, &self.tcx.sess); - Some(self.new_module( - parent, - ModuleKind::Def(def_kind, def_id, name), - expn_id, - self.def_span(def_id), - // FIXME: Account for `#[no_implicit_prelude]` attributes. - parent.map_or(false, |module| module.no_implicit_prelude), - )) - } - _ => None, + // Query `def_kind` is not used because query system overhead is too expensive here. + let def_kind = self.cstore().def_kind_untracked(def_id); + if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind { + let parent = self + .tcx + .opt_parent(def_id) + .map(|parent_id| self.get_nearest_non_block_module(parent_id)); + // Query `expn_that_defined` is not used because + // hashing spans in its result is expensive. + let expn_id = self.cstore().expn_that_defined_untracked(def_id, &self.tcx.sess); + return Some(self.new_module( + parent, + ModuleKind::Def(def_kind, def_id, self.tcx.item_name(def_id)), + expn_id, + self.def_span(def_id), + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.map_or(false, |module| module.no_implicit_prelude), + )); } - } else { - None } + + None } pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { @@ -204,6 +197,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) { + // Query `module_children` is not used because hashing spans in its result is expensive. let children = Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.tcx.sess)); for child in children { @@ -570,7 +564,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ast::UseTreeKind::Glob => { let kind = ImportKind::Glob { - is_prelude: self.r.tcx.sess.contains_name(&item.attrs, sym::prelude_import), + is_prelude: attr::contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(None), id, }; @@ -685,7 +679,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { expansion.to_expn_id(), item.span, parent.no_implicit_prelude - || self.r.tcx.sess.contains_name(&item.attrs, sym::no_implicit_prelude), + || attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); @@ -750,7 +744,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. let mut ctor_vis = if vis.is_public() - && self.r.tcx.sess.contains_name(&item.attrs, sym::non_exhaustive) + && attr::contains_name(&item.attrs, sym::non_exhaustive) { ty::Visibility::Restricted(CRATE_DEF_ID) } else { @@ -1168,12 +1162,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { - if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro) { + if attr::contains_name(&item.attrs, sym::proc_macro) { return Some((MacroKind::Bang, item.ident, item.span)); - } else if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro_attribute) { + } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = self.r.tcx.sess.find_by_name(&item.attrs, sym::proc_macro_derive) - { + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { if let Some(ident) = nested_meta.ident() { return Some((MacroKind::Derive, ident, ident.span)); @@ -1228,7 +1221,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { if macro_rules { let ident = ident.normalize_to_macros_2_0(); self.r.macro_names.insert(ident); - let is_macro_export = self.r.tcx.sess.contains_name(&item.attrs, sym::macro_export); + let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { ty::Visibility::Public } else { @@ -1488,13 +1481,12 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.visibilities.insert(def_id, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. - let ctor_vis = if vis.is_public() - && self.r.tcx.sess.contains_name(&variant.attrs, sym::non_exhaustive) - { - ty::Visibility::Restricted(CRATE_DEF_ID) - } else { - vis - }; + let ctor_vis = + if vis.is_public() && attr::contains_name(&variant.attrs, sym::non_exhaustive) { + ty::Visibility::Restricted(CRATE_DEF_ID) + } else { + vis + }; // Define a constructor name in the value namespace. if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b2578e4c4b4..dbf6cec788b 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -32,9 +32,10 @@ use rustc_ast::visit::{self, Visitor}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{pluralize, MultiSpan}; +use rustc_hir::def::{DefKind, Res}; use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, DUMMY_SP}; struct UnusedImport<'a> { @@ -58,6 +59,7 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> { base_use_tree: Option<&'a ast::UseTree>, base_id: ast::NodeId, item_span: Span, + base_use_is_pub: bool, } struct ExternCrateToLint { @@ -110,6 +112,35 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { unused: Default::default(), }) } + + fn check_import_as_underscore(&mut self, item: &ast::UseTree, id: ast::NodeId) { + match item.kind { + ast::UseTreeKind::Simple(Some(ident)) => { + if ident.name == kw::Underscore + && !self + .r + .import_res_map + .get(&id) + .map(|per_ns| { + per_ns.iter().filter_map(|res| res.as_ref()).any(|res| { + matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) + }) + }) + .unwrap_or(false) + { + self.unused_import(self.base_id).add(id); + } + } + ast::UseTreeKind::Nested(ref items) => self.check_imports_as_underscore(items), + _ => {} + } + } + + fn check_imports_as_underscore(&mut self, items: &[(ast::UseTree, ast::NodeId)]) { + for (item, id) in items { + self.check_import_as_underscore(item, *id); + } + } } impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { @@ -119,7 +150,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { // whether they're used or not. Also ignore imports with a dummy span // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. - ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return, + ast::ItemKind::Use(..) if item.span.is_dummy() => return, + ast::ItemKind::Use(..) => self.base_use_is_pub = item.vis.kind.is_pub(), ast::ItemKind::ExternCrate(orig_name) => { self.extern_crate_items.push(ExternCrateToLint { id: item.id, @@ -146,6 +178,11 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { self.base_use_tree = Some(use_tree); } + if self.base_use_is_pub { + self.check_import_as_underscore(use_tree, id); + return; + } + if let ast::UseTreeKind::Nested(ref items) = use_tree.kind { if items.is_empty() { self.unused_import(self.base_id).add(id); @@ -300,6 +337,7 @@ impl Resolver<'_, '_> { base_use_tree: None, base_id: ast::DUMMY_NODE_ID, item_span: DUMMY_SP, + base_use_is_pub: false, }; visit::walk_crate(&mut visitor, krate); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 4bb252bfb29..a1ae9b8a521 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -4,6 +4,7 @@ use rustc_ast::visit; use rustc_ast::visit::Visitor; use rustc_ast::Crate; use rustc_ast::EnumDef; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; @@ -70,11 +71,11 @@ impl Resolver<'_, '_> { impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { /// Fills the `Resolver::effective_visibilities` table with public & exported items /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we - /// need access to a TyCtxt for that. + /// need access to a TyCtxt for that. Returns the set of ambiguous re-exports. pub(crate) fn compute_effective_visibilities<'c>( r: &'r mut Resolver<'a, 'tcx>, krate: &'c Crate, - ) { + ) -> FxHashSet<Interned<'a, NameBinding<'a>>> { let mut visitor = EffectiveVisibilitiesVisitor { r, def_effective_visibilities: Default::default(), @@ -93,18 +94,26 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } visitor.r.effective_visibilities = visitor.def_effective_visibilities; + let mut exported_ambiguities = FxHashSet::default(); + // Update visibilities for import def ids. These are not used during the // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based // information, but are used by later passes. Effective visibility of an import def id // is the maximum value among visibilities of bindings corresponding to that def id. for (binding, eff_vis) in visitor.import_effective_visibilities.iter() { let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; - if let Some(node_id) = import.id() { - r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) + if !binding.is_ambiguity() { + if let Some(node_id) = import.id() { + r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) + } + } else if binding.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { + exported_ambiguities.insert(*binding); } } info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities); + + exported_ambiguities } /// Update effective visibilities of bindings in the given module, @@ -115,21 +124,44 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { let resolutions = self.r.resolutions(module); for (_, name_resolution) in resolutions.borrow().iter() { - if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() { - // Set the given effective visibility level to `Level::Direct` and - // sets the rest of the `use` chain to `Level::Reexported` until - // we hit the actual exported item. - let mut parent_id = ParentId::Def(module_id); - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { - let binding_id = ImportId::new_unchecked(binding); - self.update_import(binding_id, parent_id); - - parent_id = ParentId::Import(binding_id); - binding = nested_binding; - } + if let Some(mut binding) = name_resolution.borrow().binding() { + if !binding.is_ambiguity() { + // Set the given effective visibility level to `Level::Direct` and + // sets the rest of the `use` chain to `Level::Reexported` until + // we hit the actual exported item. + let mut parent_id = ParentId::Def(module_id); + while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind + { + let binding_id = ImportId::new_unchecked(binding); + self.update_import(binding_id, parent_id); + + parent_id = ParentId::Import(binding_id); + binding = nested_binding; + } + + if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { + self.update_def(def_id, binding.vis.expect_local(), parent_id); + } + } else { + // Put the root ambiguity binding and all reexports leading to it into the + // table. They are used by the `ambiguous_glob_reexports` lint. For all + // bindings added to the table here `is_ambiguity` returns true. + let mut parent_id = ParentId::Def(module_id); + while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind + { + let binding_id = ImportId::new_unchecked(binding); + self.update_import(binding_id, parent_id); - if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { - self.update_def(def_id, binding.vis.expect_local(), parent_id); + if binding.ambiguity.is_some() { + // Stop at the root ambiguity, further bindings in the chain should not + // be reexported because the root ambiguity blocks any access to them. + // (Those further bindings are most likely not ambiguities themselves.) + break; + } + + parent_id = ParentId::Import(binding_id); + binding = nested_binding; + } } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 5d40c6e4e48..bc17ce571a7 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -19,7 +19,9 @@ use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_middle::metadata::ModChild; use rustc_middle::span_bug; use rustc_middle::ty; -use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS}; +use rustc_session::lint::builtin::{ + AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS, +}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; @@ -85,20 +87,28 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { Single { ref source, ref target, + ref source_bindings, + ref target_bindings, ref type_ns_only, ref nested, ref id, - // Ignore the following to avoid an infinite loop while printing. - source_bindings: _, - target_bindings: _, } => f .debug_struct("Single") .field("source", source) .field("target", target) + // Ignore the nested bindings to avoid an infinite loop while printing. + .field( + "source_bindings", + &source_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))), + ) + .field( + "target_bindings", + &target_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))), + ) .field("type_ns_only", type_ns_only) .field("nested", nested) .field("id", id) - .finish_non_exhaustive(), + .finish(), Glob { ref is_prelude, ref max_vis, ref id } => f .debug_struct("Glob") .field("is_prelude", is_prelude) @@ -415,13 +425,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. pub(crate) fn resolve_imports(&mut self) { - let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1; - while self.indeterminate_imports.len() < prev_num_indeterminates { - prev_num_indeterminates = self.indeterminate_imports.len(); + let mut prev_indeterminate_count = usize::MAX; + let mut indeterminate_count = self.indeterminate_imports.len() * 3; + while indeterminate_count < prev_indeterminate_count { + prev_indeterminate_count = indeterminate_count; + indeterminate_count = 0; for import in mem::take(&mut self.indeterminate_imports) { - match self.resolve_import(&import) { - true => self.determined_imports.push(import), - false => self.indeterminate_imports.push(import), + let import_indeterminate_count = self.resolve_import(&import); + indeterminate_count += import_indeterminate_count; + match import_indeterminate_count { + 0 => self.determined_imports.push(import), + _ => self.indeterminate_imports.push(import), } } } @@ -498,6 +512,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + pub(crate) fn check_reexport_ambiguities( + &mut self, + exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>, + ) { + for module in self.arenas.local_modules().iter() { + module.for_each_child(self, |this, ident, ns, binding| { + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some((amb_binding, _)) = binding.ambiguity + && binding.res() != Res::Err + && exported_ambiguities.contains(&Interned::new_unchecked(binding)) + { + this.lint_buffer.buffer_lint_with_diagnostic( + AMBIGUOUS_GLOB_REEXPORTS, + import.root_id, + import.root_span, + "ambiguous glob re-exports", + BuiltinLintDiagnostics::AmbiguousGlobReexports { + name: ident.to_string(), + namespace: ns.descr().to_string(), + first_reexport_span: import.root_span, + duplicate_reexport_span: amb_binding.span, + }, + ); + } + }); + } + } + fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) { if errors.is_empty() { return; @@ -573,9 +615,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { diag.emit(); } - /// Attempts to resolve the given import, returning true if its resolution is determined. - /// If successful, the resolved bindings are written into the module. - fn resolve_import(&mut self, import: &'a Import<'a>) -> bool { + /// Attempts to resolve the given import, returning: + /// - `0` means its resolution is determined. + /// - Other values mean that indeterminate exists under certain namespaces. + /// + /// Meanwhile, if resolve successful, the resolved bindings are written + /// into the module. + fn resolve_import(&mut self, import: &'a Import<'a>) -> usize { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&import.module_path), @@ -593,8 +639,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match path_res { PathResult::Module(module) => module, - PathResult::Indeterminate => return false, - PathResult::NonModule(..) | PathResult::Failed { .. } => return true, + PathResult::Indeterminate => return 3, + PathResult::NonModule(..) | PathResult::Failed { .. } => return 0, } }; @@ -610,12 +656,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } => (source, target, source_bindings, target_bindings, type_ns_only), ImportKind::Glob { .. } => { self.resolve_glob_import(import); - return true; + return 0; } _ => unreachable!(), }; - let mut indeterminate = false; + let mut indeterminate_count = 0; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { if let Err(Undetermined) = source_bindings[ns].get() { @@ -638,7 +684,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let parent = import.parent_scope.module; match source_bindings[ns].get() { - Err(Undetermined) => indeterminate = true, + Err(Undetermined) => indeterminate_count += 1, // Don't update the resolution, because it was never added. Err(Determined) if target.name == kw::Underscore => {} Ok(binding) if binding.is_importable() => { @@ -662,7 +708,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }); - !indeterminate + indeterminate_count } /// Performs final import resolution, consistency checks and error reporting. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index eff10e5af9f..4ca54bab31a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -590,7 +590,6 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { parent_scope: ParentScope<'a>, /// The current set of local scopes for types and values. - /// FIXME #4948: Reuse ribs to avoid allocation. ribs: PerNS<Vec<Rib<'a>>>, /// Previous poped `rib`, only used for diagnostic. @@ -1478,8 +1477,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } else { LifetimeUseSet::Many }), - LifetimeRibKind::Generics { .. } => None, - LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => { + LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ConstGeneric => None, + LifetimeRibKind::AnonConst => { span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind) } }) @@ -4236,7 +4236,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { { return; } - ResolveDocLinks::Exported if !maybe_exported.eval(self.r) => { + ResolveDocLinks::Exported + if !maybe_exported.eval(self.r) + && !rustdoc::has_primitive_or_keyword_docs(attrs) => + { return; } ResolveDocLinks::ExportedMetadata diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 805c2ff280d..df7681dc426 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1289,25 +1289,41 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { let span = find_span(&source, err); err.span_label(self.r.def_span(def_id), &format!("`{path_str}` defined here")); - let (tail, descr, applicability) = match source { - PathSource::Pat | PathSource::TupleStruct(..) => { - ("", "pattern", Applicability::MachineApplicable) - } - _ => (": val", "literal", Applicability::HasPlaceholders), - }; + let (tail, descr, applicability, old_fields) = match source { + PathSource::Pat => ("", "pattern", Applicability::MachineApplicable, None), + PathSource::TupleStruct(_, args) => ( + "", + "pattern", + Applicability::MachineApplicable, + Some( + args.iter() + .map(|a| self.r.tcx.sess.source_map().span_to_snippet(*a).ok()) + .collect::<Vec<Option<String>>>(), + ), + ), + _ => (": val", "literal", Applicability::HasPlaceholders, None), + }; let field_ids = self.r.field_def_ids(def_id); let (fields, applicability) = match field_ids { - Some(field_ids) => ( - field_ids - .iter() - .map(|&field_id| { - format!("{}{tail}", self.r.tcx.item_name(field_id)) - }) - .collect::<Vec<String>>() - .join(", "), - applicability, - ), + Some(field_ids) => { + let fields = field_ids.iter().map(|&id| self.r.tcx.item_name(id)); + + let fields = if let Some(old_fields) = old_fields { + fields + .enumerate() + .map(|(idx, new)| (new, old_fields.get(idx))) + .map(|(new, old)| { + let new = new.to_ident_string(); + if let Some(Some(old)) = old && new != *old { format!("{}: {}", new, old) } else { new } + }) + .collect::<Vec<String>>() + } else { + fields.map(|f| format!("{f}{tail}")).collect::<Vec<String>>() + }; + + (fields.join(", "), applicability) + } None => ("/* fields */".to_string(), Applicability::HasPlaceholders), }; let pad = match field_ids { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cd90fd3ef84..0e84432a5b4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -23,7 +23,7 @@ extern crate tracing; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; -use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; +use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -1168,7 +1168,7 @@ impl<'tcx> Resolver<'_, 'tcx> { if let Some(def_id) = def_id.as_local() { self.item_generics_num_lifetimes[&def_id] } else { - self.cstore().item_generics_num_lifetimes(def_id, self.tcx.sess) + self.tcx.generics_of(def_id).own_counts().lifetimes } } @@ -1180,7 +1180,8 @@ impl<'tcx> Resolver<'_, 'tcx> { impl<'a, 'tcx> Resolver<'a, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - krate: &Crate, + attrs: &[ast::Attribute], + crate_span: Span, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); @@ -1189,8 +1190,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None, ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), ExpnId::root(), - krate.spans.inner_span, - tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude), + crate_span, + attr::contains_name(attrs, sym::no_implicit_prelude), &mut module_map, ); let empty_module = arenas.new_module( @@ -1222,9 +1223,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .map(|(name, _)| (Ident::from_str(name), Default::default())) .collect(); - if !tcx.sess.contains_name(&krate.attrs, sym::no_core) { + if !attr::contains_name(attrs, sym::no_core) { extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); - if !tcx.sess.contains_name(&krate.attrs, sym::no_std) { + if !attr::contains_name(attrs, sym::no_std) { extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); } } @@ -1474,9 +1475,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub fn resolve_crate(&mut self, krate: &Crate) { self.tcx.sess.time("resolve_crate", || { self.tcx.sess.time("finalize_imports", || self.finalize_imports()); - self.tcx.sess.time("compute_effective_visibilities", || { + let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || { EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); + self.tcx.sess.time("check_reexport_ambiguities", || { + self.check_reexport_ambiguities(exported_ambiguities) + }); self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate)); self.tcx.sess.time("resolve_main", || self.resolve_main()); @@ -1871,7 +1875,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn def_span(&self, def_id: DefId) -> Span { match def_id.as_local() { Some(def_id) => self.tcx.source_span(def_id), - None => self.cstore().get_span_untracked(def_id, self.tcx.sess), + // Query `def_span` is not used because hashing its result span is expensive. + None => self.cstore().def_span_untracked(def_id, self.tcx.sess), } } @@ -1906,10 +1911,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return v.clone(); } - let attr = self - .cstore() - .item_attrs_untracked(def_id, self.tcx.sess) - .find(|a| a.has_name(sym::rustc_legacy_const_generics))?; + let attr = self.tcx.get_attr(def_id, sym::rustc_legacy_const_generics)?; let mut ret = Vec::new(); for meta in attr.meta_item_list()? { match meta.lit()?.kind { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 37153854f7e..48707d37a10 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,7 +5,7 @@ use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment}; -use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId}; +use rustc_ast::{self as ast, attr, Inline, ItemKind, ModKind, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::intern::Interned; @@ -112,8 +112,8 @@ fn fast_print_path(path: &ast::Path) -> Symbol { pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); - let krate = tcx.crate_for_resolver(()).borrow(); - for attr in tcx.sess.filter_by_name(&krate.attrs, sym::register_tool) { + let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); + for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) { for nested_meta in attr.meta_item_list().unwrap_or_default() { match nested_meta.ident() { Some(ident) => { @@ -703,7 +703,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => { check_consistency(self, &path, path_span, kind, initial_res, res) } - path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { + path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => { let mut suggestion = None; let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { // try to suggest if it's not a macro, maybe a function diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index b8853c1744c..44a27bbc175 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -3,7 +3,7 @@ use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxHashMap; use rustc_span::def_id::DefId; -use rustc_span::symbol::{kw, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::{cmp, mem}; @@ -26,11 +26,13 @@ pub enum DocFragmentKind { #[derive(Clone, PartialEq, Eq, Debug)] pub struct DocFragment { pub span: Span, - /// The module this doc-comment came from. - /// - /// This allows distinguishing between the original documentation and a pub re-export. - /// If it is `None`, the item was not re-exported. - pub parent_module: Option<DefId>, + /// The item this doc-comment came from. + /// Used to determine the scope in which doc links in this fragment are resolved. + /// Typically filled for reexport docs when they are merged into the docs of the + /// original reexported item. + /// If the id is not filled, which happens for the original reexported item, then + /// it has to be taken from somewhere else during doc link resolution. + pub item_id: Option<DefId>, pub doc: Symbol, pub kind: DocFragmentKind, pub indent: usize, @@ -186,7 +188,7 @@ pub fn attrs_to_doc_fragments<'a>( ) -> (Vec<DocFragment>, ast::AttrVec) { let mut doc_fragments = Vec::new(); let mut other_attrs = ast::AttrVec::new(); - for (attr, parent_module) in attrs { + for (attr, item_id) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { let doc = beautify_doc_string(doc_str, comment_kind); let kind = if attr.is_doc_comment() { @@ -194,7 +196,7 @@ pub fn attrs_to_doc_fragments<'a>( } else { DocFragmentKind::RawDoc }; - let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 }; + let fragment = DocFragment { span: attr.span, doc, kind, item_id, indent: 0 }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -216,7 +218,7 @@ pub fn prepare_to_doc_link_resolution( ) -> FxHashMap<Option<DefId>, String> { let mut res = FxHashMap::default(); for fragment in doc_fragments { - let out_str = res.entry(fragment.parent_module).or_default(); + let out_str = res.entry(fragment.item_id).or_default(); add_doc_fragment(out_str, fragment); } res @@ -337,6 +339,20 @@ pub fn inner_docs(attrs: &[ast::Attribute]) -> bool { attrs.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == ast::AttrStyle::Inner) } +/// Has `#[doc(primitive)]` or `#[doc(keyword)]`. +pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool { + for attr in attrs { + if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() { + for item in items { + if item.has_name(sym::primitive) || item.has_name(sym::keyword) { + return true; + } + } + } + } + false +} + /// Simplified version of the corresponding function in rustdoc. /// If the rustdoc version returns a successful result, this function must return the same result. /// Otherwise this function may return anything. diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index d8db86c5f62..9e337dde995 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -24,5 +24,9 @@ termize = "0.1.1" [target.'cfg(unix)'.dependencies] libc = "0.2" -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["libloaderapi"] } +[target.'cfg(windows)'.dependencies.windows] +version = "0.46.0" +features = [ + "Win32_Foundation", + "Win32_System_LibraryLoader", +] diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 868ffdf0f1d..a262c06d91f 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -67,12 +67,11 @@ pub enum LinkagePreference { #[derive(Debug, Encodable, Decodable, HashStable_Generic)] pub struct NativeLib { pub kind: NativeLibKind, - pub name: Option<Symbol>, + pub name: Symbol, /// If packed_bundled_libs enabled, actual filename of library is stored. pub filename: Option<Symbol>, pub cfg: Option<ast::MetaItem>, pub foreign_module: Option<DefId>, - pub wasm_import_module: Option<Symbol>, pub verbatim: Option<bool>, pub dll_imports: Vec<DllImport>, } @@ -81,6 +80,10 @@ impl NativeLib { pub fn has_modifiers(&self) -> bool { self.verbatim.is_some() || self.kind.has_modifiers() } + + pub fn wasm_import_module(&self) -> Option<Symbol> { + if self.kind == NativeLibKind::WasmImportModule { Some(self.name) } else { None } + } } /// Different ways that the PE Format can decorate a symbol name. diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index f1fbf38217d..2404928b254 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -1,5 +1,6 @@ //! A module for searching for libraries +use rustc_fs_util::try_canonicalize; use smallvec::{smallvec, SmallVec}; use std::env; use std::fs; @@ -87,42 +88,45 @@ fn current_dll_path() -> Result<PathBuf, String> { use std::ffi::OsString; use std::io; use std::os::windows::prelude::*; - use std::ptr; - use winapi::um::libloaderapi::{ - GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + use windows::{ + core::PCWSTR, + Win32::Foundation::HINSTANCE, + Win32::System::LibraryLoader::{ + GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + }, }; + let mut module = HINSTANCE::default(); unsafe { - let mut module = ptr::null_mut(); - let r = GetModuleHandleExW( + GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - current_dll_path as usize as *mut _, + PCWSTR(current_dll_path as *mut u16), &mut module, - ); - if r == 0 { - return Err(format!("GetModuleHandleExW failed: {}", io::Error::last_os_error())); - } - let mut space = Vec::with_capacity(1024); - let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32); - if r == 0 { - return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error())); - } - let r = r as usize; - if r >= space.capacity() { - return Err(format!("our buffer was too small? {}", io::Error::last_os_error())); - } - space.set_len(r); - let os = OsString::from_wide(&space); - Ok(PathBuf::from(os)) + ) } + .ok() + .map_err(|e| e.to_string())?; + + let mut filename = vec![0; 1024]; + let n = unsafe { GetModuleFileNameW(module, &mut filename) } as usize; + if n == 0 { + return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error())); + } + if n >= filename.capacity() { + return Err(format!("our buffer was too small? {}", io::Error::last_os_error())); + } + + filename.truncate(n); + + Ok(OsString::from_wide(&filename).into()) } pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> { let target = crate::config::host_triple(); let mut sysroot_candidates: SmallVec<[PathBuf; 2]> = smallvec![get_or_default_sysroot().expect("Failed finding sysroot")]; - let path = current_dll_path().and_then(|s| s.canonicalize().map_err(|e| e.to_string())); + let path = current_dll_path().and_then(|s| try_canonicalize(s).map_err(|e| e.to_string())); if let Ok(dll) = path { // use `parent` twice to chop off the file name and then also the // directory containing the dll which should be either `lib` or `bin`. @@ -157,7 +161,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> { pub fn get_or_default_sysroot() -> Result<PathBuf, String> { // Follow symlinks. If the resolved path is relative, make it absolute. fn canonicalize(path: PathBuf) -> PathBuf { - let path = fs::canonicalize(&path).unwrap_or(path); + let path = try_canonicalize(&path).unwrap_or(path); // See comments on this target function, but the gist is that // gcc chokes on verbatim paths which fs::canonicalize generates // so we try to avoid those kinds of paths. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b466a3fcdee..c75af48e80a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -4,6 +4,7 @@ use crate::early_error; use crate::lint; use crate::search_paths::SearchPath; use crate::utils::NativeLib; +use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{LanguageIdentifier, TerminalUrl}; use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{ @@ -365,6 +366,7 @@ mod desc { pub const parse_number: &str = "a number"; pub const parse_opt_number: &str = parse_number; pub const parse_threads: &str = parse_number; + pub const parse_time_passes_format: &str = "`text` (default) or `json`"; pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_opt_panic_strategy: &str = parse_panic_strategy; @@ -829,6 +831,21 @@ mod parse { true } + pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool { + match v { + None => true, + Some("json") => { + *slot = TimePassesFormat::Json; + true + } + Some("text") => { + *slot = TimePassesFormat::Text; + true + } + Some(_) => false, + } + } + pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool { match v { None => true, @@ -1422,6 +1439,9 @@ options! { fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), + flatten_format_args: bool = (false, parse_bool, [TRACKED], + "flatten nested format_args!() and literals into a simplified format_args!() call \ + (default: no)"), force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], @@ -1706,6 +1726,8 @@ options! { "measure time of each LLVM pass (default: no)"), time_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each rustc pass (default: no)"), + time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED], + "the format to use for -Z time-passes (`text` (default) or `json`)"), tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED], "sets a tiny, non-configurable limit for const eval; useful for compiler tests"), #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")] diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index c3f0c4b58f5..fdb9fae44e1 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -5,7 +5,7 @@ use crate::errors::{ InvalidCharacterInCrateName, }; use crate::Session; -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use std::path::{Path, PathBuf}; @@ -56,7 +56,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol { // the command line over one found in the #[crate_name] attribute. If we // find both we ensure that they're the same later on as well. let attr_crate_name = - sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s))); + attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s))); if let Some(ref s) = sess.opts.crate_name { let s = Symbol::intern(s); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index fdacf814dd6..5730df9d5c6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -30,7 +30,7 @@ use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; use rustc_span::edition::Edition; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span}; -use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; +use rustc_span::{SourceFileHashAlgorithm, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; use rustc_target::spec::{ @@ -1003,40 +1003,6 @@ impl Session { || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) } - pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool { - [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] - .iter() - .any(|kind| attr.has_name(*kind)) - } - - pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool { - attrs.iter().any(|item| item.has_name(name)) - } - - pub fn find_by_name<'a>( - &'a self, - attrs: &'a [Attribute], - name: Symbol, - ) -> Option<&'a Attribute> { - attrs.iter().find(|attr| attr.has_name(name)) - } - - pub fn filter_by_name<'a>( - &'a self, - attrs: &'a [Attribute], - name: Symbol, - ) -> impl Iterator<Item = &'a Attribute> { - attrs.iter().filter(move |attr| attr.has_name(name)) - } - - pub fn first_attr_value_str_by_name( - &self, - attrs: &[Attribute], - name: Symbol, - ) -> Option<Symbol> { - attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str()) - } - pub fn diagnostic_width(&self) -> usize { let default_column_width = 140; if let Some(width) = self.opts.diagnostic_width { @@ -1487,7 +1453,10 @@ pub fn build_session( CguReuseTracker::new_disabled() }; - let prof = SelfProfilerRef::new(self_profiler, sopts.unstable_opts.time_passes); + let prof = SelfProfilerRef::new( + self_profiler, + sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format), + ); let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") { Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate, diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index b996d36a318..1d15e2c28d8 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -1,5 +1,6 @@ use crate::session::Session; use rustc_data_structures::profiling::VerboseTimingGuard; +use rustc_fs_util::try_canonicalize; use std::path::{Path, PathBuf}; impl Session { @@ -37,6 +38,10 @@ pub enum NativeLibKind { /// Argument which is passed to linker, relative order with libraries and other arguments /// is preserved LinkArg, + + /// Module imported from WebAssembly + WasmImportModule, + /// The library kind wasn't specified, `Dylib` is currently used as a default. Unspecified, } @@ -50,7 +55,10 @@ impl NativeLibKind { NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => { as_needed.is_some() } - NativeLibKind::RawDylib | NativeLibKind::Unspecified | NativeLibKind::LinkArg => false, + NativeLibKind::RawDylib + | NativeLibKind::Unspecified + | NativeLibKind::LinkArg + | NativeLibKind::WasmImportModule => false, } } @@ -91,7 +99,7 @@ pub struct CanonicalizedPath { impl CanonicalizedPath { pub fn new(path: &Path) -> Self { - Self { original: path.to_owned(), canonicalized: std::fs::canonicalize(path).ok() } + Self { original: path.to_owned(), canonicalized: try_canonicalize(path).ok() } } pub fn canonicalized(&self) -> &PathBuf { diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index ae81d95e279..98d6e0ab117 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -18,3 +18,4 @@ tracing = "0.1" sha1 = "0.10.0" sha2 = "0.10.1" md5 = { package = "md-5", version = "0.10.0" } +indexmap = { version = "1.9.1" } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 162c15574b5..b2c58caff2e 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,13 +1,17 @@ use crate::{HashStableContext, Symbol}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::unhash::Unhasher; use rustc_data_structures::AtomicRef; use rustc_index::vec::Idx; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::borrow::Borrow; use std::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::{BuildHasherDefault, Hash, Hasher}; + +pub type StableCrateIdMap = + indexmap::IndexMap<StableCrateId, CrateNum, BuildHasherDefault<Unhasher>>; rustc_index::newtype_index! { #[custom_encodable] diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 9f22e9776d4..d727aba6de5 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -880,7 +880,7 @@ impl Span { pub fn fresh_expansion(self, expn_id: LocalExpnId) -> Span { HygieneData::with(|data| { self.with_ctxt(data.apply_mark( - SyntaxContext::root(), + self.ctxt(), expn_id.to_expn_id(), Transparency::Transparent, )) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 873cd33f6a4..02cffc762be 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -795,6 +795,18 @@ impl Span { }) } + /// Splits a span into two composite spans around a certain position. + pub fn split_at(self, pos: u32) -> (Span, Span) { + let len = self.hi().0 - self.lo().0; + debug_assert!(pos <= len); + + let split_pos = BytePos(self.lo().0 + pos); + ( + Span::new(self.lo(), split_pos, self.ctxt(), self.parent()), + Span::new(split_pos, self.hi(), self.ctxt(), self.parent()), + ) + } + /// Returns a `Span` that would enclose both `self` and `end`. /// /// Note that this can also be used to extend the span "backwards": diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index a1cb810a429..ee895f53eba 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -448,25 +448,36 @@ impl SourceMap { sp: Span, filename_display_pref: FileNameDisplayPreference, ) -> String { - if self.files.borrow().source_files.is_empty() || sp.is_dummy() { - return "no-location".to_string(); - } + let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp); + + let file_name = match source_file { + Some(sf) => sf.name.display(filename_display_pref).to_string(), + None => return "no-location".to_string(), + }; - let lo = self.lookup_char_pos(sp.lo()); - let hi = self.lookup_char_pos(sp.hi()); format!( - "{}:{}:{}{}", - lo.file.name.display(filename_display_pref), - lo.line, - lo.col.to_usize() + 1, + "{file_name}:{lo_line}:{lo_col}{}", if let FileNameDisplayPreference::Short = filename_display_pref { String::new() } else { - format!(": {}:{}", hi.line, hi.col.to_usize() + 1) + format!(": {hi_line}:{hi_col}") } ) } + pub fn span_to_location_info( + &self, + sp: Span, + ) -> (Option<Lrc<SourceFile>>, usize, usize, usize, usize) { + if self.files.borrow().source_files.is_empty() || sp.is_dummy() { + return (None, 0, 0, 0, 0); + } + + let lo = self.lookup_char_pos(sp.lo()); + let hi = self.lookup_char_pos(sp.hi()); + (Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1) + } + /// Format the span location suitable for embedding in build artifacts pub fn span_to_embeddable_string(&self, sp: Span) -> String { self.span_to_string(sp, FileNameDisplayPreference::Remapped) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0154c719ef6..4a1abdf6318 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -984,6 +984,7 @@ symbols! { never_type_fallback, new, new_binary, + new_const, new_debug, new_display, new_lower_exp, @@ -1043,6 +1044,7 @@ symbols! { optin_builtin_traits, option, option_env, + option_payload_ptr, options, or, or_patterns, diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index c6899f8f244..b4d5b7f3621 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -53,7 +53,7 @@ impl SymbolNamesTest<'_> { // The formatting of `tag({})` is chosen so that tests can elect // to test the entirety of the string, if they choose, or else just // some subset. - for attr in tcx.get_attrs(def_id.to_def_id(), SYMBOL_NAME) { + for attr in tcx.get_attrs(def_id, SYMBOL_NAME) { let def_id = def_id.to_def_id(); let instance = Instance::new( def_id, @@ -79,7 +79,7 @@ impl SymbolNamesTest<'_> { } } - for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) { + for attr in tcx.get_attrs(def_id, DEF_PATH) { tcx.sess.emit_err(TestOutput { span: attr.span, kind: Kind::DefPath, diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 568c916a163..4e7a8d166ae 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bitflags = "1.2.1" tracing = "0.1" serde_json = "1.0.59" +rustc_fs_util = { path = "../rustc_fs_util" } rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f3304e91429..2553b11d878 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -40,6 +40,7 @@ use crate::json::{Json, ToJson}; use crate::spec::abi::{lookup as lookup_abi, Abi}; use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_fs_util::try_canonicalize; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::symbol::{sym, Symbol}; use serde_json::Value; @@ -2949,7 +2950,7 @@ impl TargetTriple { /// Creates a target triple from the passed target path. pub fn from_path(path: &Path) -> Result<Self, io::Error> { - let canonicalized_path = path.canonicalize()?; + let canonicalized_path = try_canonicalize(path)?; let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| { io::Error::new( io::ErrorKind::InvalidInput, diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs index ab7c08958fa..0585ed76fe8 100644 --- a/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs @@ -2,7 +2,7 @@ use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { Target { - llvm_target: "riscv64gc-unknown-fuchsia".into(), + llvm_target: "riscv64-unknown-fuchsia".into(), pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), arch: "riscv64".into(), diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 9b47c7299bb..911cc0b88c4 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -8,26 +8,16 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryRes use rustc_middle::traits::query::Fallible; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, ToPredicate}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; use std::fmt::Debug; pub use rustc_infer::infer::*; pub trait InferCtxtExt<'tcx> { - fn type_is_copy_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool; + fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; - fn type_is_sized_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool; + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; /// Check whether a `ty` implements given trait(trait_def_id). /// The inputs are: @@ -46,13 +36,9 @@ pub trait InferCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> traits::EvaluationResult; } + impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { - fn type_is_copy_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool { + fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); if !(param_env, ty).needs_infer() { @@ -65,17 +51,12 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // rightly refuses to work with inference variables, but // moves_by_default has a cache, which we want to use in other // cases. - traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) } - fn type_is_sized_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool { + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span) + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) } #[instrument(level = "debug", skip(self, params), ret)] diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 891ea0cdebe..995fec78c40 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -2,7 +2,8 @@ #[cfg(doc)] use super::trait_goals::structural_traits::*; -use super::EvalCtxt; +use super::{EvalCtxt, SolverMode}; +use crate::traits::coherence; use itertools::Itertools; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; @@ -87,6 +88,8 @@ pub(super) enum CandidateSource { pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq { fn self_ty(self) -> Ty<'tcx>; + fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; @@ -209,6 +212,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + + fn consider_builtin_destruct_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -224,7 +232,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if goal.predicate.self_ty().is_ty_var() { return vec![Candidate { source: CandidateSource::BuiltinImpl, - result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(), + result: self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + .unwrap(), }]; } @@ -242,15 +252,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_object_bound_candidates(goal, &mut candidates); + self.assemble_coherence_unknowable_candidates(goal, &mut candidates); + candidates } /// If the self type of a goal is a projection, computing the relevant candidates is difficult. /// /// To deal with this, we first try to normalize the self type and add the candidates for the normalized - /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in - /// this case as projections as self types add - // FIXME complete the unfinished sentence above + /// self type to the list of candidates in case that succeeds. We also have to consider candidates with the + /// projection as a self type as well fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>( &mut self, goal: Goal<'tcx, G>, @@ -261,8 +272,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else { return }; - self.probe(|this| { - let normalized_ty = this.next_ty_infer(); + + self.probe(|ecx| { + let normalized_ty = ecx.next_ty_infer(); let normalizes_to_goal = goal.with( tcx, ty::Binder::dummy(ty::ProjectionPredicate { @@ -270,28 +282,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { term: normalized_ty.into(), }), ); - let normalization_certainty = match this.evaluate_goal(normalizes_to_goal) { - Ok((_, certainty)) => certainty, - Err(NoSolution) => return, - }; - let normalized_ty = this.resolve_vars_if_possible(normalized_ty); - - // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. - // This doesn't work as long as we use `CandidateSource` in winnowing. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - let normalized_candidates = this.assemble_and_evaluate_candidates(goal); - for mut normalized_candidate in normalized_candidates { - normalized_candidate.result = - normalized_candidate.result.unchecked_map(|mut response| { - // FIXME: This currently hides overflow in the normalization step of the self type - // which is probably wrong. Maybe `unify_and` should actually keep overflow as - // we treat it as non-fatal anyways. - response.certainty = response.certainty.unify_and(normalization_certainty); - response - }); - candidates.push(normalized_candidate); + ecx.add_goal(normalizes_to_goal); + if let Ok(_) = ecx.try_evaluate_added_goals() { + let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); + + // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. + // This doesn't work as long as we use `CandidateSource` in winnowing. + let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); + candidates.extend(ecx.assemble_and_evaluate_candidates(goal)); } - }) + }); } fn assemble_impl_candidates<G: GoalKind<'tcx>>( @@ -345,6 +345,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_unsize_candidate(self, goal) } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) { G::consider_builtin_discriminant_kind_candidate(self, goal) + } else if lang_items.destruct_trait() == Some(trait_def_id) { + G::consider_builtin_destruct_candidate(self, goal) } else { Err(NoSolution) }; @@ -477,14 +479,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec<Candidate<'tcx>>, + ) { + match self.solver_mode() { + SolverMode::Normal => return, + SolverMode::Coherence => { + let trait_ref = goal.predicate.trait_ref(self.tcx()); + match coherence::trait_ref_is_knowable(self.tcx(), trait_ref) { + Ok(()) => {} + Err(_) => match self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + { + Ok(result) => candidates + .push(Candidate { source: CandidateSource::BuiltinImpl, result }), + // FIXME: This will be reachable at some point if we're in + // `assemble_candidates_after_normalizing_self_ty` and we get a + // universe error. We'll deal with it at this point. + Err(NoSolution) => bug!("coherence candidate resulted in NoSolution"), + }, + } + } + } + } + #[instrument(level = "debug", skip(self), ret)] - pub(super) fn merge_candidates_and_discard_reservation_impls( + pub(super) fn merge_candidates( &mut self, mut candidates: Vec<Candidate<'tcx>>, ) -> QueryResult<'tcx> { match candidates.len() { 0 => return Err(NoSolution), - 1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result), + 1 => return Ok(candidates.pop().unwrap().result), _ => {} } @@ -492,10 +520,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let mut i = 0; 'outer: while i < candidates.len() { for j in (0..candidates.len()).filter(|&j| i != j) { - if self.trait_candidate_should_be_dropped_in_favor_of( - &candidates[i], - &candidates[j], - ) { + if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j]) + { debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); candidates.swap_remove(i); continue 'outer; @@ -516,15 +542,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } else { Certainty::AMBIGUOUS }; - return self.make_canonical_response(certainty); + return self.evaluate_added_goals_and_make_canonical_response(certainty); } } - // FIXME: What if there are >1 candidates left with the same response, and one is a reservation impl? - Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result) + Ok(candidates.pop().unwrap().result) } - fn trait_candidate_should_be_dropped_in_favor_of( + fn candidate_should_be_dropped_in_favor_of( &self, candidate: &Candidate<'tcx>, other: &Candidate<'tcx>, @@ -537,18 +562,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | (CandidateSource::BuiltinImpl, _) => false, } } - - fn discard_reservation_impl(&self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> { - if let CandidateSource::Impl(def_id) = candidate.source { - if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) { - debug!("Selected reservation impl"); - // We assemble all candidates inside of a probe so by - // making a new canonical response here our result will - // have no constraints. - candidate.result = self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(); - } - } - - candidate - } } diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs index 8c3be8da16b..efecaf33ef9 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs @@ -48,7 +48,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// - `external_constraints`: additional constraints which aren't expressable /// using simple unification of inference variables. #[instrument(level = "debug", skip(self))] - pub(super) fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { + pub(super) fn evaluate_added_goals_and_make_canonical_response( + &mut self, + certainty: Certainty, + ) -> QueryResult<'tcx> { + let goals_certainty = self.try_evaluate_added_goals()?; + let certainty = certainty.unify_and(goals_certainty); + let external_constraints = self.compute_external_query_constraints()?; let response = Response { var_values: self.var_values, external_constraints, certainty }; @@ -93,20 +99,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, original_values: Vec<ty::GenericArg<'tcx>>, response: CanonicalResponse<'tcx>, - ) -> Result<Certainty, NoSolution> { + ) -> Result<(Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { let substitution = self.compute_query_response_substitution(&original_values, &response); let Response { var_values, external_constraints, certainty } = response.substitute(self.tcx(), &substitution); - self.unify_query_var_values(param_env, &original_values, var_values)?; + let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?; // FIXME: implement external constraints. let ExternalConstraintsData { region_constraints, opaque_types: _ } = external_constraints.deref(); self.register_region_constraints(region_constraints); - Ok(certainty) + Ok((certainty, nested_goals)) } /// This returns the substitutions to instantiate the bound variables of @@ -199,21 +205,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, original_values: &[ty::GenericArg<'tcx>], var_values: CanonicalVarValues<'tcx>, - ) -> Result<(), NoSolution> { + ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { assert_eq!(original_values.len(), var_values.len()); + + let mut nested_goals = vec![]; for (&orig, response) in iter::zip(original_values, var_values.var_values) { - // This can fail due to the occurs check, see - // `tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs` for an example - // where that can happen. - // - // FIXME: To deal with #105787 I also expect us to emit nested obligations here at - // some point. We can figure out how to deal with this once we actually have - // an ICE. - let nested_goals = self.eq(param_env, orig, response)?; - assert!(nested_goals.is_empty(), "{nested_goals:?}"); + nested_goals.extend(self.eq_and_get_goals(param_env, orig, response)?); } - Ok(()) + Ok(nested_goals) } fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index ca438a103cf..e47b5ae21b5 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -2,8 +2,11 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; +use rustc_infer::infer::{ + DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt, +}; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult}; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::{ @@ -13,8 +16,9 @@ use rustc_middle::ty::{ use rustc_span::DUMMY_SP; use std::ops::ControlFlow; -use super::search_graph::SearchGraph; -use super::Goal; +use super::search_graph::{self, OverflowHandler}; +use super::SolverMode; +use super::{search_graph::SearchGraph, Goal}; pub struct EvalCtxt<'a, 'tcx> { // FIXME: should be private. @@ -33,14 +37,320 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) search_graph: &'a mut SearchGraph<'tcx>, - /// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`], - /// see the comment in that method for more details. - pub in_projection_eq_hack: bool, + pub(super) nested_goals: NestedGoals<'tcx>, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub(super) enum IsNormalizesToHack { + Yes, + No, +} + +#[derive(Debug, Clone)] +pub(super) struct NestedGoals<'tcx> { + pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::ProjectionPredicate<'tcx>>>, + pub(super) goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, +} + +impl NestedGoals<'_> { + pub(super) fn new() -> Self { + Self { normalizes_to_hack_goal: None, goals: Vec::new() } + } + + pub(super) fn is_empty(&self) -> bool { + self.normalizes_to_hack_goal.is_none() && self.goals.is_empty() + } +} + +pub trait InferCtxtEvalExt<'tcx> { + /// Evaluates a goal from **outside** of the trait solver. + /// + /// Using this while inside of the solver is wrong as it uses a new + /// search graph which would break cycle detection. + fn evaluate_root_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>; +} + +impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { + #[instrument(level = "debug", skip(self))] + fn evaluate_root_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { + let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; + let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode); + + let mut ecx = EvalCtxt { + search_graph: &mut search_graph, + infcx: self, + // Only relevant when canonicalizing the response. + max_input_universe: ty::UniverseIndex::ROOT, + var_values: CanonicalVarValues::dummy(), + nested_goals: NestedGoals::new(), + }; + let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); + + assert!( + ecx.nested_goals.is_empty(), + "root `EvalCtxt` should not have any goals added to it" + ); + + assert!(search_graph.is_empty()); + result + } +} + +impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + pub(super) fn solver_mode(&self) -> SolverMode { + self.search_graph.solver_mode() + } + + /// The entry point of the solver. + /// + /// This function deals with (coinductive) cycles, overflow, and caching + /// and then calls [`EvalCtxt::compute_goal`] which contains the actual + /// logic of the solver. + /// + /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] + /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're + /// outside of it. + #[instrument(level = "debug", skip(tcx, search_graph), ret)] + fn evaluate_canonical_goal( + tcx: TyCtxt<'tcx>, + search_graph: &'a mut search_graph::SearchGraph<'tcx>, + canonical_goal: CanonicalGoal<'tcx>, + ) -> QueryResult<'tcx> { + // Deal with overflow, caching, and coinduction. + // + // The actual solver logic happens in `ecx.compute_goal`. + search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { + let intercrate = match search_graph.solver_mode() { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }; + let (ref infcx, goal, var_values) = tcx + .infer_ctxt() + .intercrate(intercrate) + .build_with_canonical(DUMMY_SP, &canonical_goal); + let mut ecx = EvalCtxt { + infcx, + var_values, + max_input_universe: canonical_goal.max_universe, + search_graph, + nested_goals: NestedGoals::new(), + }; + ecx.compute_goal(goal) + }) + } + + /// Recursively evaluates `goal`, returning whether any inference vars have + /// been constrained and the certainty of the result. + fn evaluate_goal( + &mut self, + is_normalizes_to_hack: IsNormalizesToHack, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { + let (orig_values, canonical_goal) = self.canonicalize_goal(goal); + let canonical_response = + EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + + let has_changed = !canonical_response.value.var_values.is_identity(); + let (certainty, nested_goals) = self.instantiate_and_apply_query_response( + goal.param_env, + orig_values, + canonical_response, + )?; + + // Check that rerunning this query with its inference constraints applied + // doesn't result in new inference constraints and has the same result. + // + // If we have projection goals like `<T as Trait>::Assoc == u32` we recursively + // call `exists<U> <T as Trait>::Assoc == U` to enable better caching. This goal + // could constrain `U` to `u32` which would cause this check to result in a + // solver cycle. + if cfg!(debug_assertions) + && has_changed + && is_normalizes_to_hack == IsNormalizesToHack::No + && !self.search_graph.in_cycle() + { + debug!("rerunning goal to check result is stable"); + let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); + let canonical_response = + EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + if !canonical_response.value.var_values.is_identity() { + bug!("unstable result: {goal:?} {canonical_goal:?} {canonical_response:?}"); + } + assert_eq!(certainty, canonical_response.value.certainty); + } + + Ok((has_changed, certainty, nested_goals)) + } + + fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { + let Goal { param_env, predicate } = goal; + let kind = predicate.kind(); + if let Some(kind) = kind.no_bound_vars() { + match kind { + ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + self.compute_trait_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + self.compute_projection_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + self.compute_type_outlives_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + self.compute_region_outlives_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) + } + ty::PredicateKind::Subtype(predicate) => { + self.compute_subtype_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Coerce(predicate) => { + self.compute_coerce_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::ClosureKind(def_id, substs, kind) => self + .compute_closure_kind_goal(Goal { + param_env, + predicate: (def_id, substs, kind), + }), + ty::PredicateKind::ObjectSafe(trait_def_id) => { + self.compute_object_safe_goal(trait_def_id) + } + ty::PredicateKind::WellFormed(arg) => { + self.compute_well_formed_goal(Goal { param_env, predicate: arg }) + } + ty::PredicateKind::Ambiguous => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + // FIXME: implement these predicates :) + ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } + ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self + .compute_alias_relate_goal(Goal { + param_env, + predicate: (lhs, rhs, direction), + }), + } + } else { + let kind = self.infcx.instantiate_binder_with_placeholders(kind); + let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); + self.add_goal(goal); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + } + + // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning + // the certainty of all the goals. + #[instrument(level = "debug", skip(self))] + pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> { + let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); + let mut new_goals = NestedGoals::new(); + + let response = self.repeat_while_none( + |_| Ok(Certainty::Maybe(MaybeCause::Overflow)), + |this| { + let mut has_changed = Err(Certainty::Yes); + + if let Some(goal) = goals.normalizes_to_hack_goal.take() { + let (_, certainty, nested_goals) = match this.evaluate_goal( + IsNormalizesToHack::Yes, + goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)), + ) { + Ok(r) => r, + Err(NoSolution) => return Some(Err(NoSolution)), + }; + new_goals.goals.extend(nested_goals); + + if goal.predicate.projection_ty + != this.resolve_vars_if_possible(goal.predicate.projection_ty) + { + has_changed = Ok(()) + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + let goal = this.resolve_vars_if_possible(goal); + + // The rhs of this `normalizes-to` must always be an unconstrained infer var as it is + // the hack used by `normalizes-to` to ensure that every `normalizes-to` behaves the same + // regardless of the rhs. + // + // However it is important not to unconditionally replace the rhs with a new infer var + // as otherwise we may replace the original unconstrained infer var with a new infer var + // and never propagate any constraints on the new var back to the original var. + let term = this + .term_is_fully_unconstrained(goal) + .then_some(goal.predicate.term) + .unwrap_or_else(|| { + this.next_term_infer_of_kind(goal.predicate.term) + }); + let projection_pred = ty::ProjectionPredicate { + term, + projection_ty: goal.predicate.projection_ty, + }; + new_goals.normalizes_to_hack_goal = + Some(goal.with(this.tcx(), projection_pred)); + + has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + } + } + } + + for nested_goal in goals.goals.drain(..) { + let (changed, certainty, nested_goals) = + match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) { + Ok(result) => result, + Err(NoSolution) => return Some(Err(NoSolution)), + }; + new_goals.goals.extend(nested_goals); + + if changed { + has_changed = Ok(()); + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + new_goals.goals.push(nested_goal); + has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + } + } + } + + core::mem::swap(&mut new_goals, &mut goals); + match has_changed { + Ok(()) => None, + Err(certainty) => Some(Ok(certainty)), + } + }, + ); + + self.nested_goals = goals; + response + } } impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn probe<T>(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { - self.infcx.probe(|_| f(self)) + let mut ecx = EvalCtxt { + infcx: self.infcx, + var_values: self.var_values, + max_input_universe: self.max_input_universe, + search_graph: self.search_graph, + nested_goals: self.nested_goals.clone(), + }; + self.infcx.probe(|_| f(&mut ecx)) } pub(super) fn tcx(&self) -> TyCtxt<'tcx> { @@ -61,6 +371,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) } + /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`. + /// If `kind` is an integer inference variable this will still return a ty infer var. + pub(super) fn next_term_infer_of_kind(&self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { + match kind.unpack() { + ty::TermKind::Ty(_) => self.next_ty_infer().into(), + ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(), + } + } + /// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`. /// /// This is the case if the `term` is an inference variable in the innermost universe @@ -137,6 +456,49 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self, param_env), ret)] pub(super) fn eq<T: ToTrace<'tcx>>( + &mut self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result<(), NoSolution> { + self.infcx + .at(&ObligationCause::dummy(), param_env) + .eq(DefineOpaqueTypes::No, lhs, rhs) + .map(|InferOk { value: (), obligations }| { + self.add_goals(obligations.into_iter().map(|o| o.into())); + }) + .map_err(|e| { + debug!(?e, "failed to equate"); + NoSolution + }) + } + + #[instrument(level = "debug", skip(self, param_env), ret)] + pub(super) fn sub<T: ToTrace<'tcx>>( + &mut self, + param_env: ty::ParamEnv<'tcx>, + sub: T, + sup: T, + ) -> Result<(), NoSolution> { + self.infcx + .at(&ObligationCause::dummy(), param_env) + .sub(DefineOpaqueTypes::No, sub, sup) + .map(|InferOk { value: (), obligations }| { + self.add_goals(obligations.into_iter().map(|o| o.into())); + }) + .map_err(|e| { + debug!(?e, "failed to subtype"); + NoSolution + }) + } + + /// Equates two values returning the nested goals without adding them + /// to the nested goals of the `EvalCtxt`. + /// + /// If possible, try using `eq` instead which automatically handles nested + /// goals correctly. + #[instrument(level = "debug", skip(self, param_env), ret)] + pub(super) fn eq_and_get_goals<T: ToTrace<'tcx>>( &self, param_env: ty::ParamEnv<'tcx>, lhs: T, @@ -144,7 +506,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { self.infcx .at(&ObligationCause::dummy(), param_env) - .eq(lhs, rhs) + .eq(DefineOpaqueTypes::No, lhs, rhs) .map(|InferOk { value: (), obligations }| { obligations.into_iter().map(|o| o.into()).collect() }) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 38120b9760f..76a2a587911 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,6 +1,7 @@ use std::mem; use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::Obligation; use rustc_infer::traits::{ query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, PredicateObligation, SelectionError, TraitEngine, @@ -61,7 +62,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let (changed, certainty) = match infcx.evaluate_root_goal(goal) { + let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) { Ok(result) => result, Err(NoSolution) => { errors.push(FulfillmentError { @@ -73,7 +74,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { MismatchedProjectionTypes { err: TypeError::Mismatch }, ) } - ty::PredicateKind::AliasEq(_, _) => { + ty::PredicateKind::AliasRelate(_, _, _) => { FulfillmentErrorCode::CodeProjectionError( MismatchedProjectionTypes { err: TypeError::Mismatch }, ) @@ -125,7 +126,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { continue; } }; - + // Push any nested goals that we get from unifying our canonical response + // with our obligation onto the fulfillment context. + self.obligations.extend(nested_goals.into_iter().map(|goal| { + Obligation::new( + infcx.tcx, + obligation.cause.clone(), + goal.param_env, + goal.predicate, + ) + })); has_changed |= changed; match certainty { Certainty::Yes => {} diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 55d361b1204..6a64dfdedd4 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -9,29 +9,20 @@ //! FIXME(@lcnr): Write that section. If you read this before then ask me //! about it on zulip. -// FIXME: Instead of using `infcx.canonicalize_query` we have to add a new routine which -// preserves universes and creates a unique var (in the highest universe) for each -// appearance of a region. - // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented. -use std::mem; - use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::{ CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData, - Goal, MaybeCause, QueryResult, Response, + Goal, QueryResult, Response, }; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, }; -use rustc_span::DUMMY_SP; -use crate::solve::search_graph::OverflowHandler; use crate::traits::ObligationCause; mod assembly; @@ -42,9 +33,22 @@ mod project_goals; mod search_graph; mod trait_goals; -pub use eval_ctxt::EvalCtxt; +pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt}; pub use fulfill::FulfillmentCtxt; +#[derive(Debug, Clone, Copy)] +enum SolverMode { + /// Ordinary trait solving, using everywhere except for coherence. + Normal, + /// Trait solving during coherence. There are a few notable differences + /// between coherence and ordinary trait solving. + /// + /// Most importantly, trait solving during coherence must not be incomplete, + /// i.e. return `Err(NoSolution)` for goals for which a solution exists. + /// This means that we must not make any guesses or arbitrary choices. + Coherence, +} + trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; } @@ -57,180 +61,18 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { } } -pub trait InferCtxtEvalExt<'tcx> { - /// Evaluates a goal from **outside** of the trait solver. - /// - /// Using this while inside of the solver is wrong as it uses a new - /// search graph which would break cycle detection. - fn evaluate_root_goal( - &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution>; -} - -impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { - fn evaluate_root_goal( - &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution> { - let mut search_graph = search_graph::SearchGraph::new(self.tcx); - - let result = EvalCtxt { - search_graph: &mut search_graph, - infcx: self, - // Only relevant when canonicalizing the response. - max_input_universe: ty::UniverseIndex::ROOT, - var_values: CanonicalVarValues::dummy(), - in_projection_eq_hack: false, - } - .evaluate_goal(goal); - - assert!(search_graph.is_empty()); - result - } -} - impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { - /// The entry point of the solver. - /// - /// This function deals with (coinductive) cycles, overflow, and caching - /// and then calls [`EvalCtxt::compute_goal`] which contains the actual - /// logic of the solver. - /// - /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] - /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're - /// outside of it. - #[instrument(level = "debug", skip(tcx, search_graph), ret)] - fn evaluate_canonical_goal( - tcx: TyCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph<'tcx>, - canonical_goal: CanonicalGoal<'tcx>, - ) -> QueryResult<'tcx> { - // Deal with overflow, caching, and coinduction. - // - // The actual solver logic happens in `ecx.compute_goal`. - search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { - let (ref infcx, goal, var_values) = - tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); - let mut ecx = EvalCtxt { - infcx, - var_values, - max_input_universe: canonical_goal.max_universe, - search_graph, - in_projection_eq_hack: false, - }; - ecx.compute_goal(goal) - }) - } - - /// Recursively evaluates `goal`, returning whether any inference vars have - /// been constrained and the certainty of the result. - fn evaluate_goal( - &mut self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution> { - let (orig_values, canonical_goal) = self.canonicalize_goal(goal); - let canonical_response = - EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; - - let has_changed = !canonical_response.value.var_values.is_identity(); - let certainty = self.instantiate_and_apply_query_response( - goal.param_env, - orig_values, - canonical_response, - )?; - - // Check that rerunning this query with its inference constraints applied - // doesn't result in new inference constraints and has the same result. - // - // If we have projection goals like `<T as Trait>::Assoc == u32` we recursively - // call `exists<U> <T as Trait>::Assoc == U` to enable better caching. This goal - // could constrain `U` to `u32` which would cause this check to result in a - // solver cycle. - if cfg!(debug_assertions) - && has_changed - && !self.in_projection_eq_hack - && !self.search_graph.in_cycle() - && false - { - let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); - let canonical_response = - EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; - if !canonical_response.value.var_values.is_identity() { - bug!("unstable result: {goal:?} {canonical_goal:?} {canonical_response:?}"); - } - assert_eq!(certainty, canonical_response.value.certainty); - } - - Ok((has_changed, certainty)) - } - - fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { - let Goal { param_env, predicate } = goal; - let kind = predicate.kind(); - if let Some(kind) = kind.no_bound_vars() { - match kind { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { - self.compute_trait_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { - self.compute_projection_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { - self.compute_type_outlives_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { - self.compute_region_outlives_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) - } - ty::PredicateKind::Subtype(predicate) => { - self.compute_subtype_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Coerce(predicate) => { - self.compute_coerce_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::ClosureKind(def_id, substs, kind) => self - .compute_closure_kind_goal(Goal { - param_env, - predicate: (def_id, substs, kind), - }), - ty::PredicateKind::ObjectSafe(trait_def_id) => { - self.compute_object_safe_goal(trait_def_id) - } - ty::PredicateKind::WellFormed(arg) => { - self.compute_well_formed_goal(Goal { param_env, predicate: arg }) - } - ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS), - // FIXME: implement these predicates :) - ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => { - self.make_canonical_response(Certainty::Yes) - } - ty::PredicateKind::TypeWellFormedFromEnv(..) => { - bug!("TypeWellFormedFromEnv is only used for Chalk") - } - ty::PredicateKind::AliasEq(lhs, rhs) => { - self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) }) - } - } - } else { - let kind = self.infcx.instantiate_binder_with_placeholders(kind); - let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); - let (_, certainty) = self.evaluate_goal(goal)?; - self.make_canonical_response(certainty) - } - } - + #[instrument(level = "debug", skip(self))] fn compute_type_outlives_goal( &mut self, goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { let ty::OutlivesPredicate(ty, lt) = goal.predicate; self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + #[instrument(level = "debug", skip(self))] fn compute_region_outlives_goal( &mut self, goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, @@ -239,9 +81,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { &ObligationCause::dummy(), ty::Binder::dummy(goal.predicate), ); - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + #[instrument(level = "debug", skip(self))] fn compute_coerce_goal( &mut self, goal: Goal<'tcx, CoercePredicate<'tcx>>, @@ -256,6 +99,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }) } + #[instrument(level = "debug", skip(self))] fn compute_subtype_goal( &mut self, goal: Goal<'tcx, SubtypePredicate<'tcx>>, @@ -263,18 +107,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() { // FIXME: Do we want to register a subtype relation between these vars? // That won't actually reflect in the query response, so it seems moot. - self.make_canonical_response(Certainty::AMBIGUOUS) + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), goal.param_env) - .sub(goal.predicate.a, goal.predicate.b)?; - self.evaluate_all_and_make_canonical_response( - obligations.into_iter().map(|pred| pred.into()).collect(), - ) + self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } + #[instrument(level = "debug", skip(self))] fn compute_closure_kind_goal( &mut self, goal: Goal<'tcx, (DefId, ty::SubstsRef<'tcx>, ty::ClosureKind)>, @@ -283,23 +123,25 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let found_kind = substs.as_closure().kind_ty().to_opt_closure_kind(); let Some(found_kind) = found_kind else { - return self.make_canonical_response(Certainty::AMBIGUOUS); + return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); }; if found_kind.extends(expected_kind) { - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) } } + #[instrument(level = "debug", skip(self))] fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { if self.tcx().check_is_object_safe(trait_def_id) { - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) } } + #[instrument(level = "debug", skip(self))] fn compute_well_formed_goal( &mut self, goal: Goal<'tcx, ty::GenericArg<'tcx>>, @@ -309,63 +151,103 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal.param_env, goal.predicate, ) { - Some(obligations) => self.evaluate_all_and_make_canonical_response( - obligations.into_iter().map(|o| o.into()).collect(), - ), - None => self.make_canonical_response(Certainty::AMBIGUOUS), + Some(obligations) => { + self.add_goals(obligations.into_iter().map(|o| o.into())); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS), } } #[instrument(level = "debug", skip(self), ret)] - fn compute_alias_eq_goal( + fn compute_alias_relate_goal( &mut self, - goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>, + goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, ) -> QueryResult<'tcx> { let tcx = self.tcx(); + // We may need to invert the alias relation direction if dealing an alias on the RHS. + enum Invert { + No, + Yes, + } + let evaluate_normalizes_to = + |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| { + debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); + let result = ecx.probe(|ecx| { + let other = match direction { + // This is purely an optimization. + ty::AliasRelationDirection::Equate => other, + + ty::AliasRelationDirection::Subtype => { + let fresh = ecx.next_term_infer_of_kind(other); + let (sub, sup) = match invert { + Invert::No => (fresh, other), + Invert::Yes => (other, fresh), + }; + ecx.sub(goal.param_env, sub, sup)?; + fresh + } + }; + ecx.add_goal(goal.with( + tcx, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: alias, + term: other, + }), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }); + debug!("evaluate_normalizes_to({alias}, {other}, {direction:?}) -> {result:?}"); + result + }; - let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| { - debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); - let r = ecx.probe(|ecx| { - let (_, certainty) = ecx.evaluate_goal(goal.with( - tcx, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty: alias, - term: other, - }), - ))?; - ecx.make_canonical_response(certainty) - }); - debug!("evaluate_normalizes_to(..) -> {:?}", r); - r - }; + let (lhs, rhs, direction) = goal.predicate; - if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() { + if lhs.is_infer() || rhs.is_infer() { bug!( - "`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated" + "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated" ); } - match ( - goal.predicate.0.to_alias_term_no_opaque(tcx), - goal.predicate.1.to_alias_term_no_opaque(tcx), - ) { - (None, None) => bug!("`AliasEq` goal without an alias on either lhs or rhs"), - (Some(alias), None) => evaluate_normalizes_to(self, alias, goal.predicate.1), - (None, Some(alias)) => evaluate_normalizes_to(self, alias, goal.predicate.0), - (Some(alias_lhs), Some(alias_rhs)) => { - debug!("compute_alias_eq_goal: both sides are aliases"); + match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) { + (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"), + + // RHS is not a projection, only way this is true is if LHS normalizes-to RHS + (Some(alias_lhs), None) => { + evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No) + } - let mut candidates = Vec::with_capacity(3); + // LHS is not a projection, only way this is true is if RHS normalizes-to LHS + (None, Some(alias_rhs)) => { + evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes) + } - // Evaluate all 3 potential candidates for the alias' being equal - candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1)); - candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0)); - candidates.push(self.probe(|this| { - debug!("compute_alias_eq_goal: alias defids are equal, equating substs"); - let nested_goals = this.eq(goal.param_env, alias_lhs, alias_rhs)?; - this.evaluate_all_and_make_canonical_response(nested_goals) - })); + (Some(alias_lhs), Some(alias_rhs)) => { + debug!("compute_alias_relate_goal: both sides are aliases"); + + let candidates = vec![ + // LHS normalizes-to RHS + evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No), + // RHS normalizes-to RHS + evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes), + // Relate via substs + self.probe(|ecx| { + debug!( + "compute_alias_relate_goal: alias defids are equal, equating substs" + ); + + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(goal.param_env, alias_lhs, alias_rhs)?; + } + } + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }), + ]; debug!(?candidates); self.try_merge_responses(candidates.into_iter()) @@ -379,62 +261,31 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>, ) -> QueryResult<'tcx> { let (ct, ty) = goal.predicate; - let nested_goals = self.eq(goal.param_env, ct.ty(), ty)?; - self.evaluate_all_and_make_canonical_response(nested_goals) + self.eq(goal.param_env, ct.ty(), ty)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } impl<'tcx> EvalCtxt<'_, 'tcx> { - // Recursively evaluates a list of goals to completion, returning the certainty - // of all of the goals. - fn evaluate_all( - &mut self, - mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, - ) -> Result<Certainty, NoSolution> { - let mut new_goals = Vec::new(); - self.repeat_while_none( - |_| Ok(Certainty::Maybe(MaybeCause::Overflow)), - |this| { - let mut has_changed = Err(Certainty::Yes); - for goal in goals.drain(..) { - let (changed, certainty) = match this.evaluate_goal(goal) { - Ok(result) => result, - Err(NoSolution) => return Some(Err(NoSolution)), - }; - - if changed { - has_changed = Ok(()); - } + #[instrument(level = "debug", skip(self))] + fn set_normalizes_to_hack_goal(&mut self, goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>) { + assert!( + self.nested_goals.normalizes_to_hack_goal.is_none(), + "attempted to set the projection eq hack goal when one already exists" + ); + self.nested_goals.normalizes_to_hack_goal = Some(goal); + } - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - new_goals.push(goal); - has_changed = has_changed.map_err(|c| c.unify_and(certainty)); - } - } - } - - match has_changed { - Ok(()) => { - mem::swap(&mut new_goals, &mut goals); - None - } - Err(certainty) => Some(Ok(certainty)), - } - }, - ) + #[instrument(level = "debug", skip(self))] + fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) { + self.nested_goals.goals.push(goal); } - // Recursively evaluates a list of goals to completion, making a query response. - // - // This is just a convenient way of calling [`EvalCtxt::evaluate_all`], - // then [`EvalCtxt::make_canonical_response`]. - fn evaluate_all_and_make_canonical_response( - &mut self, - goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, - ) -> QueryResult<'tcx> { - self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty)) + #[instrument(level = "debug", skip(self, goals))] + fn add_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) { + let current_len = self.nested_goals.goals.len(); + self.nested_goals.goals.extend(goals); + debug!("added_goals={:?}", &self.nested_goals.goals[current_len..]); } fn try_merge_responses( @@ -447,7 +298,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return Err(NoSolution); } - // FIXME(-Ztreat-solver=next): We should instead try to find a `Certainty::Yes` response with + // FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with // a subset of the constraints that all the other responses have. let one = candidates[0]; if candidates[1..].iter().all(|resp| resp == &one) { @@ -466,7 +317,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }); // FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the // responses and use that for the constraints of this ambiguous response. - let response = self.make_canonical_response(certainty); + let response = self.evaluate_added_goals_and_make_canonical_response(certainty); if let Ok(response) = &response { assert!(response.has_no_inference_or_external_constraints()); } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index dbb8e722c8f..525b3105538 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -20,6 +20,7 @@ use rustc_span::{sym, DUMMY_SP}; use std::iter; impl<'tcx> EvalCtxt<'_, 'tcx> { + #[instrument(level = "debug", skip(self), ret)] pub(super) fn compute_projection_goal( &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, @@ -33,56 +34,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // projection cache in the solver. if self.term_is_fully_unconstrained(goal) { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates_and_discard_reservation_impls(candidates) + self.merge_candidates(candidates) } else { let predicate = goal.predicate; - let unconstrained_rhs = match predicate.term.unpack() { - ty::TermKind::Ty(_) => self.next_ty_infer().into(), - ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(), - }; - let unconstrained_predicate = ty::Clause::Projection(ProjectionPredicate { + let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term); + let unconstrained_predicate = ProjectionPredicate { projection_ty: goal.predicate.projection_ty, term: unconstrained_rhs, - }); - let (_has_changed, normalize_certainty) = self.in_projection_eq_hack(|this| { - this.evaluate_goal(goal.with(this.tcx(), unconstrained_predicate)) - })?; - - let nested_eq_goals = self.eq(goal.param_env, unconstrained_rhs, predicate.term)?; - let eval_certainty = self.evaluate_all(nested_eq_goals)?; - self.make_canonical_response(normalize_certainty.unify_and(eval_certainty)) - } - } - - /// This sets a flag used by a debug assert in [`EvalCtxt::evaluate_goal`], - /// see the comment in that method for more details. - fn in_projection_eq_hack<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { - self.in_projection_eq_hack = true; - let result = f(self); - self.in_projection_eq_hack = false; - result - } - - /// After normalizing the projection to `normalized_alias` with the given - /// `normalization_certainty`, constrain the inference variable `term` to it - /// and return a query response. - fn eq_term_and_make_canonical_response( - &mut self, - goal: Goal<'tcx, ProjectionPredicate<'tcx>>, - normalization_certainty: Certainty, - normalized_alias: impl Into<ty::Term<'tcx>>, - ) -> QueryResult<'tcx> { - // The term of our goal should be fully unconstrained, so this should never fail. - // - // It can however be ambiguous when the `normalized_alias` contains a projection. - let nested_goals = self - .eq(goal.param_env, goal.predicate.term, normalized_alias.into()) - .expect("failed to unify with unconstrained term"); - - let unify_certainty = - self.evaluate_all(nested_goals).expect("failed to unify with unconstrained term"); + }; - self.make_canonical_response(normalization_certainty.unify_and(unify_certainty)) + self.set_normalizes_to_hack_goal(goal.with(self.tcx(), unconstrained_predicate)); + self.try_evaluate_added_goals()?; + self.eq(goal.param_env, unconstrained_rhs, predicate.term)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } } } @@ -91,6 +56,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { self.self_ty() } + fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + self.projection_ty.trait_ref(tcx) + } + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } @@ -111,19 +80,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx.probe(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(poly_projection_pred); - let mut nested_goals = ecx.eq( + ecx.eq( goal.param_env, goal.predicate.projection_ty, assumption_projection_pred.projection_ty, )?; - nested_goals.extend(requirements); - let subst_certainty = ecx.evaluate_all(nested_goals)?; - - ecx.eq_term_and_make_canonical_response( - goal, - subst_certainty, - assumption_projection_pred.term, - ) + ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?; + ecx.add_goals(requirements); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } else { Err(NoSolution) @@ -139,21 +103,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { && poly_projection_pred.projection_def_id() == goal.predicate.def_id() { ecx.probe(|ecx| { + let tcx = ecx.tcx(); + let assumption_projection_pred = ecx.instantiate_binder_with_infer(poly_projection_pred); - let mut nested_goals = ecx.eq( + ecx.eq( goal.param_env, goal.predicate.projection_ty, assumption_projection_pred.projection_ty, )?; - let tcx = ecx.tcx(); let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { bug!("expected object type in `consider_object_bound_candidate`"); }; - nested_goals.extend( + ecx.add_goals( structural_traits::predicates_for_object_candidate( - ecx, + &ecx, goal.param_env, goal.predicate.projection_ty.trait_ref(tcx), bounds, @@ -161,14 +126,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)), ); - - let subst_certainty = ecx.evaluate_all(nested_goals)?; - - ecx.eq_term_and_make_canonical_response( - goal, - subst_certainty, - assumption_projection_pred.term, - ) + ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } else { Err(NoSolution) @@ -195,16 +154,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let mut nested_goals = ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; + ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; + let where_clause_bounds = tcx .predicates_of(impl_def_id) .instantiate(tcx, impl_substs) .predicates .into_iter() .map(|pred| goal.with(tcx, pred)); - - nested_goals.extend(where_clause_bounds); - let match_impl_certainty = ecx.evaluate_all(nested_goals)?; + ecx.add_goals(where_clause_bounds); // In case the associated item is hidden due to specialization, we have to // return ambiguity this would otherwise be incomplete, resulting in @@ -216,7 +174,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal.predicate.def_id(), impl_def_id )? else { - return ecx.make_canonical_response(match_impl_certainty.unify_and(Certainty::AMBIGUOUS)); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); }; if !assoc_def.item.defaultness(tcx).has_value() { @@ -263,7 +221,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty.map_bound(|ty| ty.into()) }; - ecx.eq_term_and_make_canonical_response(goal, match_impl_certainty, term.subst(tcx, substs)) + ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -308,14 +267,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - let Some(tupled_inputs_and_output) = - structural_traits::extract_tupled_inputs_and_output_from_callable( - tcx, - goal.predicate.self_ty(), - goal_kind, - )? else { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); - }; + let tupled_inputs_and_output = + match structural_traits::extract_tupled_inputs_and_output_from_callable( + tcx, + goal.predicate.self_ty(), + goal_kind, + )? { + Some(tupled_inputs_and_output) => tupled_inputs_and_output, + None => { + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + }; let output_is_sized_pred = tupled_inputs_and_output .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); @@ -380,13 +343,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { [ty::GenericArg::from(goal.predicate.self_ty())], )); - let (_, is_sized_certainty) = - ecx.evaluate_goal(goal.with(tcx, sized_predicate))?; - return ecx.eq_term_and_make_canonical_response( - goal, - is_sized_certainty, - tcx.types.unit, - ); + ecx.add_goal(goal.with(tcx, sized_predicate)); + ecx.eq(goal.param_env, goal.predicate.term, tcx.types.unit.into())?; + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } ty::Adt(def, substs) if def.is_struct() => { @@ -394,12 +353,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { None => tcx.types.unit, Some(field_def) => { let self_ty = field_def.ty(tcx, substs); - let new_goal = goal.with( + ecx.add_goal(goal.with( tcx, ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - ); - let (_, certainty) = ecx.evaluate_goal(new_goal)?; - return ecx.make_canonical_response(certainty); + )); + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } } } @@ -408,12 +367,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty::Tuple(elements) => match elements.last() { None => tcx.types.unit, Some(&self_ty) => { - let new_goal = goal.with( + ecx.add_goal(goal.with( tcx, ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - ); - let (_, certainty) = ecx.evaluate_goal(new_goal)?; - return ecx.make_canonical_response(certainty); + )); + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } }, @@ -426,7 +385,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ), }; - ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, metadata_ty) + ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -522,7 +482,17 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let discriminant = goal.predicate.self_ty().discriminant_ty(ecx.tcx()); - ecx.probe(|ecx| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant)) + ecx.probe(|ecx| { + ecx.eq(goal.param_env, goal.predicate.term, discriminant.into())?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + + fn consider_builtin_destruct_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Destruct` does not have an associated type: {:?}", goal); } } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index f1b840aac55..219890b9dc4 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -1,8 +1,9 @@ mod cache; mod overflow; +pub(super) use overflow::OverflowHandler; + use self::cache::ProvisionalEntry; -pub(super) use crate::solve::search_graph::overflow::OverflowHandler; use cache::ProvisionalCache; use overflow::OverflowData; use rustc_index::vec::IndexVec; @@ -11,6 +12,8 @@ use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryRes use rustc_middle::ty::TyCtxt; use std::{collections::hash_map::Entry, mem}; +use super::SolverMode; + rustc_index::newtype_index! { pub struct StackDepth {} } @@ -21,6 +24,7 @@ struct StackElem<'tcx> { } pub(super) struct SearchGraph<'tcx> { + mode: SolverMode, /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. @@ -30,18 +34,21 @@ pub(super) struct SearchGraph<'tcx> { } impl<'tcx> SearchGraph<'tcx> { - pub(super) fn new(tcx: TyCtxt<'tcx>) -> SearchGraph<'tcx> { + pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> { Self { + mode, stack: Default::default(), overflow_data: OverflowData::new(tcx), provisional_cache: ProvisionalCache::empty(), } } + pub(super) fn solver_mode(&self) -> SolverMode { + self.mode + } + pub(super) fn is_empty(&self) -> bool { - self.stack.is_empty() - && self.provisional_cache.is_empty() - && !self.overflow_data.did_overflow() + self.stack.is_empty() && self.provisional_cache.is_empty() } /// Whether we're currently in a cycle. This should only be used @@ -247,7 +254,8 @@ impl<'tcx> SearchGraph<'tcx> { // dependencies, our non-root goal may no longer appear as child of the root goal. // // See https://github.com/rust-lang/rust/pull/108071 for some additional context. - let should_cache_globally = !self.overflow_data.did_overflow() || self.stack.is_empty(); + let should_cache_globally = matches!(self.solver_mode(), SolverMode::Normal) + && (!self.overflow_data.did_overflow() || self.stack.is_empty()); if should_cache_globally { tcx.new_solver_evaluation_cache.insert( current_goal.goal, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 7878539817c..ade45d199f0 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -2,7 +2,7 @@ use std::iter; -use super::{assembly, EvalCtxt}; +use super::{assembly, EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; @@ -20,6 +20,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { self.self_ty() } + fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + self.trait_ref + } + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } @@ -43,20 +47,36 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } + let impl_polarity = tcx.impl_polarity(impl_def_id); + // An upper bound of the certainty of this goal, used to lower the certainty + // of reservation impl to ambiguous during coherence. + let maximal_certainty = match impl_polarity { + ty::ImplPolarity::Positive | ty::ImplPolarity::Negative => { + match impl_polarity == goal.predicate.polarity { + true => Certainty::Yes, + false => return Err(NoSolution), + } + } + ty::ImplPolarity::Reservation => match ecx.solver_mode() { + SolverMode::Normal => return Err(NoSolution), + SolverMode::Coherence => Certainty::AMBIGUOUS, + }, + }; + ecx.probe(|ecx| { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let mut nested_goals = - ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; + ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) .instantiate(tcx, impl_substs) .predicates .into_iter() .map(|pred| goal.with(tcx, pred)); - nested_goals.extend(where_clause_bounds); - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.add_goals(where_clause_bounds); + + ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) }) } @@ -73,13 +93,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(poly_trait_pred); - let mut nested_goals = ecx.eq( + ecx.eq( goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref, )?; - nested_goals.extend(requirements); - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.add_goals(requirements); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } else { Err(NoSolution) @@ -98,7 +118,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(poly_trait_pred); - let mut nested_goals = ecx.eq( + ecx.eq( goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref, @@ -108,9 +128,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { bug!("expected object type in `consider_object_bound_candidate`"); }; - nested_goals.extend( + ecx.add_goals( structural_traits::predicates_for_object_candidate( - ecx, + &ecx, goal.param_env, goal.predicate.trait_ref, bounds, @@ -118,8 +138,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)), ); - - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } else { Err(NoSolution) @@ -166,9 +185,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let nested_obligations = tcx .predicates_of(goal.predicate.def_id()) .instantiate(tcx, goal.predicate.trait_ref.substs); - ecx.evaluate_all_and_make_canonical_response( - nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(), - ) + ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -197,7 +215,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { if goal.predicate.self_ty().has_non_region_infer() { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } let tcx = ecx.tcx(); @@ -209,7 +227,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { && layout.layout.align().abi == usize_layout.align().abi { // FIXME: We could make this faster by making a no-constraints response - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) } @@ -221,14 +239,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - let Some(tupled_inputs_and_output) = - structural_traits::extract_tupled_inputs_and_output_from_callable( + let tupled_inputs_and_output = + match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, goal.predicate.self_ty(), goal_kind, - )? else { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); - }; + )? { + Some(a) => a, + None => { + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + }; let output_is_sized_pred = tupled_inputs_and_output .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); @@ -247,7 +269,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { if let ty::Tuple(..) = goal.predicate.self_ty().kind() { - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) } @@ -257,7 +279,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, _goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } fn consider_builtin_future_candidate( @@ -277,7 +299,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Async generator unconditionally implement `Future` // Technically, we need to check that the future output type is Sized, // but that's already proven by the generator being WF. - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } fn consider_builtin_generator_candidate( @@ -317,7 +339,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let a_ty = goal.predicate.self_ty(); let b_ty = goal.predicate.trait_ref.substs.type_at(1); if b_ty.is_ty_var() { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } ecx.probe(|ecx| { match (a_ty.kind(), b_ty.kind()) { @@ -326,7 +348,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Dyn upcasting is handled separately, since due to upcasting, // when there are two supertraits that differ by substs, we // may return more than one query response. - return Err(NoSolution); + Err(NoSolution) } // `T` -> `dyn Trait` unsizing (_, &ty::Dynamic(data, region, ty::Dyn)) => { @@ -341,29 +363,26 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let Some(sized_def_id) = tcx.lang_items().sized_trait() else { return Err(NoSolution); }; - let nested_goals: Vec<_> = data - .iter() - // Check that the type implements all of the predicates of the def-id. - // (i.e. the principal, all of the associated types match, and any auto traits) - .map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))) - .chain([ - // The type must be Sized to be unsized. - goal.with( - tcx, - ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty])), - ), - // The type must outlive the lifetime of the `dyn` we're unsizing into. - goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), - ]) - .collect(); - - ecx.evaluate_all_and_make_canonical_response(nested_goals) + // Check that the type implements all of the predicates of the def-id. + // (i.e. the principal, all of the associated types match, and any auto traits) + ecx.add_goals( + data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + ); + // The type must be Sized to be unsized. + ecx.add_goal( + goal.with(tcx, ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty]))), + ); + // The type must outlive the lifetime of the `dyn` we're unsizing into. + ecx.add_goal( + goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // `[T; n]` -> `[T]` unsizing (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { // We just require that the element type stays the same - let nested_goals = ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) @@ -397,15 +416,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Finally, we require that `TailA: Unsize<TailB>` for the tail field // types. - let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; - nested_goals.push(goal.with( + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + ecx.add_goal(goal.with( tcx, ty::Binder::dummy( tcx.mk_trait_ref(goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), ), )); - - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) @@ -417,17 +435,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Substitute just the tail field of B., and require that they're equal. let unsized_a_ty = tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied()); - let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; // Similar to ADTs, require that the rest of the fields are equal. - nested_goals.push(goal.with( + ecx.add_goal(goal.with( tcx, ty::Binder::dummy( tcx.mk_trait_ref(goal.predicate.def_id(), [*a_last_ty, *b_last_ty]), ), )); - - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } _ => Err(NoSolution), } @@ -477,12 +494,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn); // We also require that A's lifetime outlives B's lifetime. - let mut nested_obligations = ecx.eq(goal.param_env, new_a_ty, b_ty)?; - nested_obligations.push( + ecx.eq(goal.param_env, new_a_ty, b_ty)?; + ecx.add_goal( goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))), ); - - ecx.evaluate_all_and_make_canonical_response(nested_obligations) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) }; @@ -516,7 +532,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { _goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { // `DiscriminantKind` is automatically implemented for every type. - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + + fn consider_builtin_destruct_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + if !goal.param_env.is_const() { + // `Destruct` is automatically implemented for every type in + // non-const environments. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver + Err(NoSolution) + } } } @@ -530,26 +560,28 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>, ) -> QueryResult<'tcx> { - self.probe(|this| { - this.evaluate_all_and_make_canonical_response( - constituent_tys(this, goal.predicate.self_ty())? + self.probe(|ecx| { + ecx.add_goals( + constituent_tys(ecx, goal.predicate.self_ty())? .into_iter() .map(|ty| { goal.with( - this.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(this.tcx(), ty)), + ecx.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), ) }) - .collect(), - ) + .collect::<Vec<_>>(), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } + #[instrument(level = "debug", skip(self))] pub(super) fn compute_trait_goal( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, ) -> QueryResult<'tcx> { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates_and_discard_reservation_impls(candidates) + self.merge_candidates(candidates) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index d7d93377cf1..9817186b874 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -189,12 +189,28 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( goal_kind: ty::ClosureKind, ) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> { match *self_ty.kind() { - ty::FnDef(def_id, substs) => Ok(Some( - tcx.fn_sig(def_id) - .subst(tcx, substs) - .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())), - )), - ty::FnPtr(sig) => Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))), + // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. + ty::FnDef(def_id, substs) => { + let sig = tcx.fn_sig(def_id); + if sig.skip_binder().is_fn_trait_compatible() + && tcx.codegen_fn_attrs(def_id).target_features.is_empty() + { + Ok(Some( + sig.subst(tcx, substs) + .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())), + )) + } else { + Err(NoSolution) + } + } + // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. + ty::FnPtr(sig) => { + if sig.is_fn_trait_compatible() { + Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))) + } else { + Err(NoSolution) + } + } ty::Closure(_, substs) => { let closure_substs = substs.as_closure(); match closure_substs.kind_ty().to_opt_closure_kind() { @@ -333,7 +349,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> { // FIXME: Technically this folder could be fallible? let nested = self .ecx - .eq(self.param_env, alias_ty, proj.projection_ty) + .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty) .expect("expected to be able to unify goal projection with dyn's projection"); // FIXME: Technically we could register these too.. assert!(nested.is_empty(), "did not expect unification to have any nested goals"); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 1fb8659bb27..6b3a59b1ed5 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -7,6 +7,7 @@ use crate::errors::UnableToConstructConstantValue; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitableExt; @@ -179,8 +180,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { // At this point, we already have all of the bounds we need. FulfillmentContext is used // to store all of the necessary region/lifetime bounds in the InferContext, as well as // an additional sanity check. - let errors = - super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); } @@ -814,7 +816,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { - match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2) + match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::No,c1, c2) { Ok(_) => (), Err(_) => return false, @@ -830,7 +832,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // the `ParamEnv`. ty::PredicateKind::WellFormed(..) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index aeaade1d66c..98e00e8223b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -17,7 +17,7 @@ use crate::traits::{ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{DefineOpaqueTypes, DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -95,8 +95,11 @@ pub fn overlapping_impls( return None; } - let infcx = - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build(); + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .intercrate(true) + .build(); let selcx = &mut SelectionContext::new(&infcx); let overlaps = overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some(); @@ -107,8 +110,11 @@ pub fn overlapping_impls( // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - let infcx = - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build(); + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .intercrate(true) + .build(); let selcx = &mut SelectionContext::new(&infcx); selcx.enable_tracking_intercrate_ambiguity_causes(); Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap()) @@ -181,7 +187,7 @@ fn overlap_within_probe<'cx, 'tcx>( let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id); let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id); - let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?; + let obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?; debug!("overlap: unification check succeeded"); if overlap_mode.use_implicit_negative() { @@ -207,20 +213,25 @@ fn overlap_within_probe<'cx, 'tcx>( Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } -fn equate_impl_headers<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - impl1_header: &ty::ImplHeader<'tcx>, - impl2_header: &ty::ImplHeader<'tcx>, +#[instrument(level = "debug", skip(infcx), ret)] +fn equate_impl_headers<'tcx>( + infcx: &InferCtxt<'tcx>, + impl1: &ty::ImplHeader<'tcx>, + impl2: &ty::ImplHeader<'tcx>, ) -> Option<PredicateObligations<'tcx>> { - // Do `a` and `b` unify? If not, no overlap. - debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header); - selcx - .infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .define_opaque_types(true) - .eq_impl_headers(impl1_header, impl2_header) - .map(|infer_ok| infer_ok.obligations) - .ok() + let result = match (impl1.trait_ref, impl2.trait_ref) { + (Some(impl1_ref), Some(impl2_ref)) => infcx + .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) + .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref), + (None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( + DefineOpaqueTypes::Yes, + impl1.self_ty, + impl2.self_ty, + ), + _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), + }; + + result.map(|infer_ok| infer_ok.obligations).ok() } /// Given impl1 and impl2 check if both impls can be satisfied by a common type (including @@ -325,7 +336,7 @@ fn equate<'tcx>( ) -> bool { // do the impls unify? If not, not disjoint. let Ok(InferOk { obligations: more_obligations, .. }) = - infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2) + infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2) else { debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2); return true; @@ -378,7 +389,10 @@ fn resolve_negative_obligation<'tcx>( }; let param_env = o.param_env; - if !super::fully_solve_obligation(&infcx, o).is_empty() { + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligation(o); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { return false; } @@ -388,6 +402,7 @@ fn resolve_negative_obligation<'tcx>( let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id); let outlives_env = OutlivesEnvironment::with_bounds( param_env, + Some(&infcx), infcx.implied_bounds_tys(param_env, body_def_id, wf_tys), ); diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 62d5e50dbc5..8acc31cd410 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -11,7 +11,7 @@ use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, }; -use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_infer::traits::query::Fallible; use rustc_infer::traits::{ FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, @@ -128,8 +128,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { { self.infcx .at(cause, param_env) - .define_opaque_types(true) - .eq_exp(a_is_expected, a, b) + .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -142,8 +141,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { ) -> Result<(), TypeError<'tcx>> { self.infcx .at(cause, param_env) - .define_opaque_types(true) - .eq(expected, actual) + .eq(DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -157,8 +155,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { ) -> Result<(), TypeError<'tcx>> { self.infcx .at(cause, param_env) - .define_opaque_types(true) - .sub(expected, actual) + .sub(DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -172,8 +169,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { ) -> Result<(), TypeError<'tcx>> { self.infcx .at(cause, param_env) - .define_opaque_types(true) - .sup(expected, actual) + .sup(DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs index 1174efdbfa8..13607b9079a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs @@ -92,6 +92,11 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { } impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> { + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + // FIXME(deferred_projection_equality): We really should get rid of this relation. + ty::AliasRelationDirection::Equate + } + fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) { // FIXME(deferred_projection_equality) } 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 41ffaeeac1c..296fd1ed524 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1276,16 +1276,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "TypeWellFormedFromEnv predicate should only exist in the environment" ), - ty::PredicateKind::AliasEq(..) => span_bug!( + ty::PredicateKind::AliasRelate(..) => span_bug!( span, - "AliasEq predicate should never be the predicate cause of a SelectionError" + "AliasRelate predicate should never be the predicate cause of a SelectionError" ), ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - self.tcx.sess.struct_span_err( + let mut diag = self.tcx.sess.struct_span_err( span, &format!("the constant `{}` is not of type `{}`", ct, ty), - ) + ); + self.note_type_err( + &mut diag, + &obligation.cause, + None, + None, + TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())), + false, + false, + ); + diag } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 277926688e2..a9c4e126816 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -144,18 +144,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>, ) -> OnUnimplementedNote { - if self.tcx.opt_rpitit_info(obligation.cause.body_id.to_def_id()).is_some() { - return OnUnimplementedNote::default(); - } - let (def_id, substs) = self .impl_similar_to(trait_ref, obligation) .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs)); let trait_ref = trait_ref.skip_binder(); - let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); - let mut flags = - vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))]; + let mut flags = vec![]; + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, + // but I guess we could synthesize one here. We don't see any errors that rely on + // that yet, though. + let enclosure = + if let Some(body_hir) = self.tcx.opt_local_def_id_to_hir_id(obligation.cause.body_id) { + self.describe_enclosure(body_hir).map(|s| s.to_owned()) + } else { + None + }; + flags.push((sym::ItemContext, enclosure)); match obligation.cause.code() { ObligationCauseCode::BuiltinDerivedObligation(..) 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 5541c085075..be0817472ea 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -212,7 +212,7 @@ pub trait TypeErrCtxtExt<'tcx> { fn extract_callable_info( &self, - hir_id: HirId, + body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, found: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>; @@ -420,6 +420,7 @@ fn suggest_restriction<'tcx>( ) { if hir_generics.where_clause_span.from_expansion() || hir_generics.where_clause_span.desugaring_kind().is_some() + || projection.map_or(false, |projection| tcx.opt_rpitit_info(projection.def_id).is_some()) { return; } @@ -908,9 +909,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred.self_ty(), ); - let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); let Some((def_id_or_name, output, inputs)) = self.extract_callable_info( - body_hir_id, + obligation.cause.body_id, obligation.param_env, self_ty, ) else { return false; }; @@ -1112,10 +1112,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// Extracts information about a callable type for diagnostics. This is a /// heuristic -- it doesn't necessarily mean that a type is always callable, /// because the callable type must also be well-formed to be called. - // FIXME(vincenzopalazzo): move the HirId to a LocalDefId fn extract_callable_info( &self, - hir_id: HirId, + body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, found: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> { @@ -1167,7 +1166,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }) } ty::Param(param) => { - let generics = self.tcx.generics_of(hir_id.owner.to_def_id()); + let generics = self.tcx.generics_of(body_id); let name = if generics.count() > param.index as usize && let def = generics.param_at(param.index as usize, self.tcx) && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) @@ -1357,6 +1356,31 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Applicability::MaybeIncorrect, ); } else { + let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; + let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" }); + let sugg_msg = &format!( + "consider{} borrowing here", + if is_mut { " mutably" } else { "" } + ); + + // Issue #109436, we need to add parentheses properly for method calls + // for example, `foo.into()` should be `(&foo).into()` + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet( + self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)), + ) { + if snippet == "." { + err.multipart_suggestion_verbose( + sugg_msg, + vec![ + (span.shrink_to_lo(), format!("({}", sugg_prefix)), + (span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return true; + } + } + // Issue #104961, we need to add parentheses properly for compond expressions // for example, `x.starts_with("hi".to_string() + "you")` // should be `x.starts_with(&("hi".to_string() + "you"))` @@ -1373,14 +1397,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => false, }; - let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; let span = if needs_parens { span } else { span.shrink_to_lo() }; - let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" }); - let sugg_msg = &format!( - "consider{} borrowing here", - if is_mut { " mutably" } else { "" } - ); - let suggestions = if !needs_parens { vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))] } else { @@ -2944,9 +2961,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::SizedYieldType => { err.note("the yield type of a generator must have a statically known size"); } - ObligationCauseCode::SizedBoxType => { - err.note("the type of a box expression must have a statically known size"); - } ObligationCauseCode::AssignmentLhsSized => { err.note("the left-hand-side of an assignment must have a statically known size"); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 944436ab82f..07e31e87bfb 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -2,6 +2,7 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::ProjectionCacheKey; use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation}; use rustc_middle::mir::interpret::ErrorHandled; @@ -210,6 +211,29 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { type Error = FulfillmentErrorCode<'tcx>; type OUT = Outcome<Self::Obligation, Self::Error>; + /// Compared to `needs_process_obligation` this and its callees + /// contain some optimizations that come at the price of false negatives. + /// + /// They + /// - reduce branching by covering only the most common case + /// - take a read-only view of the unification tables which allows skipping undo_log + /// construction. + /// - bail out on value-cache misses in ena to avoid pointer chasing + /// - hoist RefCell locking out of the loop + #[inline] + fn skippable_obligations<'b>( + &'b self, + it: impl Iterator<Item = &'b Self::Obligation>, + ) -> usize { + let is_unchanged = self.selcx.infcx.is_ty_infer_var_definitely_unchanged(); + + it.take_while(|o| match o.stalled_on.as_slice() { + [o] => is_unchanged(*o), + _ => false, + }) + .count() + } + /// Identifies whether a predicate obligation needs processing. /// /// This is always inlined because it has a single callsite and it is @@ -337,8 +361,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } }, Some(pred) => match pred { @@ -515,7 +539,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { if let Ok(new_obligations) = infcx .at(&obligation.cause, obligation.param_env) .trace(c1, c2) - .eq(a.substs, b.substs) + .eq(DefineOpaqueTypes::No, a.substs, b.substs) { return ProcessResult::Changed(mk_pending( new_obligations.into_obligations(), @@ -524,8 +548,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } (_, Unevaluated(_)) | (Unevaluated(_), _) => (), (_, _) => { - if let Ok(new_obligations) = - infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2) + if let Ok(new_obligations) = infcx + .at(&obligation.cause, obligation.param_env) + .eq(DefineOpaqueTypes::No, c1, c2) { return ProcessResult::Changed(mk_pending( new_obligations.into_obligations(), @@ -565,12 +590,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { - match self - .selcx - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(c1, c2) - { + match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::No, + c1, + c2, + ) { Ok(inf_ok) => { ProcessResult::Changed(mk_pending(inf_ok.into_obligations())) } @@ -606,16 +630,15 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - match self - .selcx - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(ct.ty(), ty) - { + match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::No, + ct.ty(), + ty, + ) { Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError( SelectionError::Unimplemented, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 0bde43c54df..336db4fee6c 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -111,6 +111,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( // Check regions assuming the self type of the impl is WF let outlives_env = OutlivesEnvironment::with_bounds( param_env, + Some(&infcx), infcx.implied_bounds_tys( param_env, parent_cause.body_id, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index bfeda88a6d4..e8970606704 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -4,7 +4,7 @@ pub mod auto_trait; mod chalk_fulfill; -mod coherence; +pub(crate) mod coherence; pub mod const_evaluatable; mod engine; pub mod error_reporting; @@ -30,7 +30,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; -use rustc_span::def_id::{DefId, CRATE_DEF_ID}; +use rustc_span::def_id::DefId; use rustc_span::Span; use std::fmt::Debug; @@ -63,9 +63,7 @@ pub use self::util::{ elaborate_trait_ref, elaborate_trait_refs, }; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; -pub use self::util::{ - get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, -}; +pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::util::{ supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, SupertraitDefIds, Supertraits, @@ -131,29 +129,23 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, - span: Span, ) -> bool { let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty])); - pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const(), span) + pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const()) } -#[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)] +/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? +/// +/// Ping me on zulip if you want to use this method and need help with finding +/// an appropriate replacement. +#[instrument(level = "debug", skip(infcx, param_env, pred), ret)] fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>, - span: Span, ) -> bool { let has_non_region_infer = pred.has_non_region_infer(); - let obligation = Obligation { - param_env, - // We can use a dummy node-id here because we won't pay any mind - // to region obligations that arise (there shouldn't really be any - // anyhow). - cause: ObligationCause::misc(span, CRATE_DEF_ID), - recursion_depth: 0, - predicate: pred.to_predicate(infcx.tcx), - }; + let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); let result = infcx.evaluate_obligation_no_overflow(&obligation); debug!(?result); @@ -166,14 +158,13 @@ fn pred_known_to_hold_modulo_regions<'tcx>( // this function's result remains infallible, we must confirm // that guess. While imperfect, I believe this is sound. - // FIXME(@lcnr): this function doesn't seem right. - // // The handling of regions in this area of the code is terrible, // see issue #29149. We should be able to improve on this with // NLL. - let errors = fully_solve_obligation(infcx, obligation); - - match &errors[..] { + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); + match errors.as_slice() { [] => true, errors => { debug!(?errors); @@ -389,43 +380,6 @@ where Ok(resolved_value) } -/// Process an obligation (and any nested obligations that come from it) to -/// completion, returning any errors -pub fn fully_solve_obligation<'tcx>( - infcx: &InferCtxt<'tcx>, - obligation: PredicateObligation<'tcx>, -) -> Vec<FulfillmentError<'tcx>> { - fully_solve_obligations(infcx, [obligation]) -} - -/// Process a set of obligations (and any nested obligations that come from them) -/// to completion -pub fn fully_solve_obligations<'tcx>( - infcx: &InferCtxt<'tcx>, - obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, -) -> Vec<FulfillmentError<'tcx>> { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligations(obligations); - ocx.select_all_or_error() -} - -/// Process a bound (and any nested obligations that come from it) to completion. -/// This is a convenience function for traits that have no generic arguments, such -/// as auto traits, and builtin traits like Copy or Sized. -pub fn fully_solve_bound<'tcx>( - infcx: &InferCtxt<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - bound: DefId, -) -> Vec<FulfillmentError<'tcx>> { - let tcx = infcx.tcx; - let trait_ref = tcx.mk_trait_ref(bound, [ty]); - let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref)); - - fully_solve_obligation(infcx, obligation) -} - /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index a5def4151bf..5d2af5ff33c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -17,10 +17,10 @@ use rustc_errors::{DelayDm, FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; -use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; +use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -139,6 +139,10 @@ fn object_safety_violations_for_trait( if !spans.is_empty() { violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); } + let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id); + if !spans.is_empty() { + violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans)); + } violations.extend( tcx.associated_items(trait_def_id) @@ -331,7 +335,7 @@ fn predicate_references_self<'tcx>( has_self_ty(&ty.into()).then_some(sp) } - ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"), + ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"), ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) @@ -348,6 +352,21 @@ fn predicate_references_self<'tcx>( } } +fn super_predicates_have_non_lifetime_binders( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> SmallVec<[Span; 1]> { + // If non_lifetime_binders is disabled, then exit early + if !tcx.features().non_lifetime_binders { + return SmallVec::new(); + } + tcx.super_predicates_of(trait_def_id) + .predicates + .iter() + .filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span)) + .collect() +} + fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { generics_require_sized_self(tcx, trait_def_id) } @@ -376,7 +395,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index e2c198fabde..bac02f2d383 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,10 +1,9 @@ use crate::infer::InferCtxt; use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use crate::traits::query::NoSolution; -use crate::traits::ObligationCause; +use crate::traits::{ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; -use rustc_infer::infer::resolve::OpportunisticRegionResolver; -use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt}; +use rustc_middle::ty::{self, ParamEnv, Ty}; use rustc_span::def_id::LocalDefId; pub use rustc_middle::traits::query::OutlivesBound; @@ -53,10 +52,6 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { body_id: LocalDefId, ty: Ty<'tcx>, ) -> Vec<OutlivesBound<'tcx>> { - let ty = self.resolve_vars_if_possible(ty); - let ty = OpportunisticRegionResolver::new(self).fold_ty(ty); - assert!(!ty.needs_infer()); - let span = self.tcx.def_span(body_id); let result = param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) @@ -76,22 +71,23 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { if let Some(constraints) = constraints { debug!(?constraints); + if !constraints.member_constraints.is_empty() { + span_bug!(span, "{:#?}", constraints.member_constraints); + } + // Instantiation may have produced new inference variables and constraints on those // variables. Process these constraints. + let ocx = ObligationCtxt::new(self); let cause = ObligationCause::misc(span, body_id); - let errors = super::fully_solve_obligations( - self, - constraints.outlives.iter().map(|constraint| { - self.query_outlives_constraint_to_obligation( - *constraint, - cause.clone(), - param_env, - ) - }), - ); - if !constraints.member_constraints.is_empty() { - span_bug!(span, "{:#?}", constraints.member_constraints); + for &constraint in &constraints.outlives { + ocx.register_obligation(self.query_outlives_constraint_to_obligation( + constraint, + cause.clone(), + param_env, + )); } + + let errors = ocx.select_all_or_error(); if !errors.is_empty() { self.tcx.sess.delay_span_bug( span, @@ -110,7 +106,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { tys: FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx> { tys.into_iter() - .map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty)) + .map(move |ty| { + let ty = self.resolve_vars_if_possible(ty); + self.implied_outlives_bounds(param_env, body_id, ty) + }) .flatten() } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 01075d7c55a..b8d9cff9c48 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -28,6 +28,7 @@ use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::at::At; use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::ImplSourceBuiltinData; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -285,12 +286,12 @@ fn project_and_unify_type<'cx, 'tcx>( ); obligations.extend(new); - match infcx - .at(&obligation.cause, obligation.param_env) - // This is needed to support nested opaque types like `impl Fn() -> impl Trait` - .define_opaque_types(true) - .eq(normalized, actual) - { + // Need to define opaque types to support nested opaque types like `impl Fn() -> impl Trait` + match infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::Yes, + normalized, + actual, + ) { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); ProjectAndUnifyResult::Holds(obligations) @@ -467,6 +468,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx return ty; } + let (kind, data) = match *ty.kind() { + ty::Alias(kind, alias_ty) => (kind, alias_ty), + _ => return ty.super_fold_with(self), + }; + // We try to be a little clever here as a performance optimization in // cases where there are nested projections under binders. // For example: @@ -490,13 +496,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx // replace bound vars if the current type is a `Projection` and we need // to make sure we don't forget to fold the substs regardless. - match *ty.kind() { + match kind { // This is really important. While we *can* handle this, this has // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) - if !substs.has_escaping_bound_vars() => - { + ty::Opaque if !data.substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), @@ -512,8 +516,8 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx ); } - let substs = substs.fold_with(self); - let generic_ty = self.interner().type_of(def_id); + let substs = data.substs.fold_with(self); + let generic_ty = self.interner().type_of(data.def_id); let concrete_ty = generic_ty.subst(self.interner(), substs); self.depth += 1; let folded_ty = self.fold_ty(concrete_ty); @@ -522,8 +526,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx } } } + ty::Opaque => ty.super_fold_with(self), - ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => { + ty::Projection if !data.has_escaping_bound_vars() => { // This branch is *mostly* just an optimization: when we don't // have escaping bound vars, we don't need to replace them with // placeholders (see branch below). *Also*, we know that we can @@ -562,7 +567,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx normalized_ty.ty().unwrap() } - ty::Alias(ty::Projection, data) => { + ty::Projection => { // If there are escaping bound vars, we temporarily replace the // bound vars with placeholders. Note though, that in the case // that we still can't project for whatever reason (e.g. self @@ -611,8 +616,6 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx ); normalized_ty } - - _ => ty.super_fold_with(self), } } @@ -1295,7 +1298,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( ) { let tcx = selcx.tcx(); if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder { - let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id); + let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id); let trait_def_id = tcx.parent(trait_fn_def_id); let trait_substs = @@ -2064,7 +2067,11 @@ fn confirm_param_env_candidate<'cx, 'tcx>( debug!(?cache_projection, ?obligation_projection); - match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) { + match infcx.at(cause, param_env).eq( + DefineOpaqueTypes::No, + cache_projection, + obligation_projection, + ) { Ok(InferOk { value: _, obligations }) => { nested_obligations.extend(obligations); assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); @@ -2193,7 +2200,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( let tcx = selcx.tcx(); let mut obligations = data.nested; - let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id); + let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id); let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) { Ok(assoc_ty) => assoc_ty, Err(guar) => return Progress::error(tcx, guar), diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index f84b2f4428d..edbe2de8105 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,9 +1,8 @@ -use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause}; +use rustc_infer::traits::{TraitEngine, TraitEngineExt}; use rustc_middle::ty; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; -use crate::solve::InferCtxtEvalExt; use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; pub trait InferCtxtExt<'tcx> { @@ -81,27 +80,20 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { if self.tcx.trait_solver_next() { self.probe(|snapshot| { - if let Ok((_, certainty)) = - self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate)) - { - match certainty { - Certainty::Yes => { - if self.opaque_types_added_in_snapshot(snapshot) { - Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) - } else if self.region_constraints_added_in_snapshot(snapshot).is_some() - { - Ok(EvaluationResult::EvaluatedToOkModuloRegions) - } else { - Ok(EvaluationResult::EvaluatedToOk) - } - } - Certainty::Maybe(MaybeCause::Ambiguity) => { - Ok(EvaluationResult::EvaluatedToAmbig) - } - Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical), - } - } else { + let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); + fulfill_cx.register_predicate_obligation(self, obligation.clone()); + // True errors + // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK? + if !fulfill_cx.select_where_possible(self).is_empty() { Ok(EvaluationResult::EvaluatedToErr) + } else if !fulfill_cx.select_all_or_error(self).is_empty() { + Ok(EvaluationResult::EvaluatedToAmbig) + } else if self.opaque_types_added_in_snapshot(snapshot) { + Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) + } else if self.region_constraints_added_in_snapshot(snapshot).is_some() { + Ok(EvaluationResult::EvaluatedToOkModuloRegions) + } else { + Ok(EvaluationResult::EvaluatedToOk) } }) } else { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index b0cec3ce7a3..a986a9b6a71 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -197,23 +197,30 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> return Ok(*ty); } + let (kind, data) = match *ty.kind() { + ty::Alias(kind, data) => (kind, data), + _ => { + let res = ty.try_super_fold_with(self)?; + self.cache.insert(ty, res); + return Ok(res); + } + }; + // See note in `rustc_trait_selection::traits::project` about why we // wait to fold the substs. // Wrap this in a closure so we don't accidentally return from the outer function - let res = match *ty.kind() { + let res = match kind { // This is really important. While we *can* handle this, this has // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) - if !substs.has_escaping_bound_vars() => - { + ty::Opaque if !data.substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.try_super_fold_with(self)?, Reveal::All => { - let substs = substs.try_fold_with(self)?; + let substs = data.substs.try_fold_with(self)?; let recursion_limit = self.interner().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { // A closure or generator may have itself as in its upvars. @@ -228,7 +235,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> return ty.try_super_fold_with(self); } - let generic_ty = self.interner().type_of(def_id); + let generic_ty = self.interner().type_of(data.def_id); let concrete_ty = generic_ty.subst(self.interner(), substs); self.anon_depth += 1; if concrete_ty == ty { @@ -248,62 +255,22 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> } } - ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => { - // This branch is just an optimization: when we don't have escaping bound vars, - // we don't need to replace them with placeholders (see branch below). - - let tcx = self.infcx.tcx; - let data = data.try_fold_with(self)?; - - let mut orig_values = OriginalQueryValues::default(); - // HACK(matthewjasper) `'static` is special-cased in selection, - // so we cannot canonicalize it. - let c_data = self - .infcx - .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values); - debug!("QueryNormalizer: c_data = {:#?}", c_data); - debug!("QueryNormalizer: orig_values = {:#?}", orig_values); - let result = tcx.normalize_projection_ty(c_data)?; - // We don't expect ambiguity. - if result.is_ambiguous() { - // Rustdoc normalizes possibly not well-formed types, so only - // treat this as a bug if we're not in rustdoc. - if !tcx.sess.opts.actually_rustdoc { - tcx.sess.delay_span_bug( - DUMMY_SP, - format!("unexpected ambiguity: {:?} {:?}", c_data, result), - ); - } - return Err(NoSolution); - } - let InferOk { value: result, obligations } = - self.infcx.instantiate_query_response_and_region_obligations( - self.cause, - self.param_env, - &orig_values, - result, - )?; - debug!("QueryNormalizer: result = {:#?}", result); - debug!("QueryNormalizer: obligations = {:#?}", obligations); - self.obligations.extend(obligations); - - let res = result.normalized_ty; - // `tcx.normalize_projection_ty` may normalize to a type that still has - // unevaluated consts, so keep normalizing here if that's the case. - if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { - res.try_super_fold_with(self)? - } else { - res - } - } + ty::Opaque => ty.try_super_fold_with(self)?, - ty::Alias(ty::Projection, data) => { + ty::Projection => { // See note in `rustc_trait_selection::traits::project` let tcx = self.infcx.tcx; let infcx = self.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + // Just an optimization: When we don't have escaping bound vars, + // we don't need to replace them with placeholders. + let (data, maps) = if data.has_escaping_bound_vars() { + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + (data, Some((mapped_regions, mapped_types, mapped_consts))) + } else { + (data, None) + }; let data = data.try_fold_with(self)?; let mut orig_values = OriginalQueryValues::default(); @@ -337,14 +304,18 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - let res = PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - result.normalized_ty, - ); + let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps { + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + result.normalized_ty, + ) + } else { + result.normalized_ty + }; // `tcx.normalize_projection_ty` may normalize to a type that still has // unevaluated consts, so keep normalizing here if that's the case. if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { @@ -353,8 +324,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> res } } - - _ => ty.try_super_fold_with(self)?, }; self.cache.insert(ty, res); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 6bf3ed0d0e2..8f1b05c1190 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -1,8 +1,8 @@ use crate::infer::canonical::query_response; use crate::infer::{InferCtxt, InferOk}; -use crate::traits; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; +use crate::traits::ObligationCtxt; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_span::source_map::DUMMY_SP; @@ -73,7 +73,9 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - let errors = traits::fully_solve_obligations(infcx, obligations); + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligations(obligations); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.tcx.sess.diagnostic().delay_span_bug( DUMMY_SP, @@ -82,9 +84,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( } let region_obligations = infcx.take_registered_region_obligations(); - let region_constraint_data = infcx.take_and_reset_region_constraints(); - let region_constraints = query_response::make_query_region_constraints( infcx.tcx, region_obligations 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 3182af989f0..e06eff34df2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -11,7 +11,6 @@ use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_target::spec::abi::Abi; use crate::traits; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -291,6 +290,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } + // Keep this funtion in sync with extract_tupled_inputs_and_output_from_callable + // until the old solver (and thus this function) is removed. + // Okay to skip binder because what we are inspecting doesn't involve bound regions. let self_ty = obligation.self_ty().skip_binder(); match *self_ty.kind() { @@ -299,31 +301,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.ambiguous = true; // Could wind up being a fn() type. } // Provide an impl, but only for suitable `fn` pointers. - ty::FnPtr(_) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() - { + ty::FnPtr(sig) => { + if sig.is_fn_trait_compatible() { candidates.vec.push(FnPointerCandidate { is_const: false }); } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). ty::FnDef(def_id, _) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() + if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible() + && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { - if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { - candidates - .vec - .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); - } + candidates + .vec + .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); } } _ => {} diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index ee41d840bae..eb354bc3f50 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -8,8 +8,8 @@ //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; +use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::ty::{ self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt, @@ -18,7 +18,7 @@ use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; -use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::vtable::{ count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset, VtblSegment, @@ -177,7 +177,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(placeholder_trait_predicate, candidate) + .sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); @@ -253,15 +253,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - ensure_sufficient_stack(|| { - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) - }) + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) } else { vec![] }; @@ -462,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(obligation_trait_ref, upcast_trait_ref) + .sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); @@ -827,11 +825,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); + // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs self.infcx .at(&obligation.cause, obligation.param_env) - // needed for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs - .define_opaque_types(true) - .sup(obligation_trait_ref, expected_trait_ref) + .sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref) .map(|InferOk { mut obligations, .. }| { obligations.extend(nested); obligations @@ -896,7 +893,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .sup(target, source_trait) + .sup(DefineOpaqueTypes::No, target, source_trait) .map_err(|_| Unimplemented)?; nested.extend(obligations); @@ -995,7 +992,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .sup(target, source_trait) + .sup(DefineOpaqueTypes::No, target, source_trait) .map_err(|_| Unimplemented)?; nested.extend(obligations); @@ -1066,7 +1063,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(b, a) + .eq(DefineOpaqueTypes::No, b, a) .map_err(|_| Unimplemented)?; nested.extend(obligations); } @@ -1114,19 +1111,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(target, new_struct) + .eq(DefineOpaqueTypes::No, target, new_struct) .map_err(|_| Unimplemented)?; nested.extend(obligations); // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate. - nested.push(predicate_for_trait_def( + let tail_unsize_obligation = obligation.with( tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - [source_tail, target_tail], - )); + tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]), + ); + nested.push(tail_unsize_obligation); } // `(.., T)` -> `(.., U)` @@ -1144,21 +1138,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(target, new_tuple) + .eq(DefineOpaqueTypes::No, target, new_tuple) .map_err(|_| Unimplemented)?; nested.extend(obligations); - // Construct the nested `T: Unsize<U>` predicate. - nested.push(ensure_sufficient_stack(|| { - predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - [a_last, b_last], - ) - })); + // Add a nested `T: Unsize<U>` predicate. + let last_unsize_obligation = obligation + .with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last])); + nested.push(last_unsize_obligation); } _ => bug!("source: {source}, target: {target}"), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 38cdaddc1e7..4f429f018ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -17,7 +17,7 @@ use super::project; use super::project::normalize_with_depth_to; use super::project::ProjectionTyObligation; use super::util; -use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use super::util::closure_trait_ref_and_return_type; use super::wf; use super::{ ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, @@ -38,6 +38,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::traits::TraitEngine; use rustc_infer::traits::TraitEngineExt; @@ -594,7 +595,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_predicates_recursively_in_new_solver(predicates) } else { let mut result = EvaluatedToOk; - for obligation in predicates { + for mut obligation in predicates { + obligation.set_depth_from_parent(stack.depth()); let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; if let EvaluatedToErr = eval { // fast-path - EvaluatedToErr is the top of the lattice, @@ -616,6 +618,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); fulfill_cx.register_predicate_obligations(self.infcx, predicates); // True errors + // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK? if !fulfill_cx.select_where_possible(self.infcx).is_empty() { return Ok(EvaluatedToErr); } @@ -660,12 +663,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( - previous_stack, - obligations.into_iter(), - ) + Ok(Ok(InferOk { obligations, .. })) => { + self.evaluate_predicates_recursively(previous_stack, obligations) } Ok(Err(_)) => Ok(EvaluatedToErr), Err(..) => Ok(EvaluatedToAmbig), @@ -676,12 +675,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( - previous_stack, - obligations.into_iter(), - ) + Ok(Ok(InferOk { obligations, .. })) => { + self.evaluate_predicates_recursively(previous_stack, obligations) } Ok(Err(_)) => Ok(EvaluatedToErr), Err(..) => Ok(EvaluatedToAmbig), @@ -754,9 +749,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { arg, obligation.cause.span, ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - + Some(obligations) => { cache.wf_args.borrow_mut().push((arg, previous_stack.depth())); let result = self.evaluate_predicates_recursively(previous_stack, obligations); @@ -825,10 +818,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - self.add_depth( - subobligations.iter_mut(), - obligation.recursion_depth, - ); + // Need to explicitly set the depth of nested goals here as + // projection obligations can cycle by themselves and in + // `evaluate_predicates_recursively` we only add the depth + // for parent trait goals because only these get added to the + // `TraitObligationStackList`. + for subobligation in subobligations.iter_mut() { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } let res = self.evaluate_predicates_recursively( previous_stack, subobligations, @@ -908,38 +905,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if a.def.did == b.def.did && tcx.def_kind(a.def.did) == DefKind::AssocConst => { - if let Ok(new_obligations) = self + if let Ok(InferOk { obligations, value: () }) = self .infcx .at(&obligation.cause, obligation.param_env) .trace(c1, c2) - .eq(a.substs, b.substs) + .eq(DefineOpaqueTypes::No, a.substs, b.substs) { - let mut obligations = new_obligations.obligations; - self.add_depth( - obligations.iter_mut(), - obligation.recursion_depth, - ); return self.evaluate_predicates_recursively( previous_stack, - obligations.into_iter(), + obligations, ); } } (_, Unevaluated(_)) | (Unevaluated(_), _) => (), (_, _) => { - if let Ok(new_obligations) = self + if let Ok(InferOk { obligations, value: () }) = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(c1, c2) + .eq(DefineOpaqueTypes::No, c1, c2) { - let mut obligations = new_obligations.obligations; - self.add_depth( - obligations.iter_mut(), - obligation.recursion_depth, - ); return self.evaluate_predicates_recursively( previous_stack, - obligations.into_iter(), + obligations, ); } } @@ -964,8 +951,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { - match self.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2) - { + match self.infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::No, + c1, + c2, + ) { Ok(inf_ok) => self.evaluate_predicates_recursively( previous_stack, inf_ok.into_obligations(), @@ -988,12 +978,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - match self.infcx.at(&obligation.cause, obligation.param_env).eq(ct.ty(), ty) { + match self.infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::No, + ct.ty(), + ty, + ) { Ok(inf_ok) => self.evaluate_predicates_recursively( previous_stack, inf_ok.into_obligations(), @@ -1358,24 +1352,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result); } - /// For various reasons, it's possible for a subobligation - /// to have a *lower* recursion_depth than the obligation used to create it. - /// Projection sub-obligations may be returned from the projection cache, - /// which results in obligations with an 'old' `recursion_depth`. - /// Additionally, methods like `InferCtxt.subtype_predicate` produce - /// subobligations without taking in a 'parent' depth, causing the - /// generated subobligations to have a `recursion_depth` of `0`. - /// - /// To ensure that obligation_depth never decreases, we force all subobligations - /// to have at least the depth of the original obligation. - fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>( - &self, - it: I, - min_depth: usize, - ) { - it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); - } - fn check_recursion_depth<T>( &self, depth: usize, @@ -1751,7 +1727,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); self.infcx .at(&obligation.cause, obligation.param_env) - .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) + .sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound) .map(|InferOk { obligations: _, value: () }| { // This method is called within a probe, so we can't have // inference variables and placeholders escape. @@ -1813,7 +1789,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let is_match = self .infcx .at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate, infer_projection) + .sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection) .map_or(false, |InferOk { obligations, value: () }| { self.evaluate_predicates_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), @@ -2432,15 +2408,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { placeholder_ty, ) }); - let placeholder_obligation = predicate_for_trait_def( + + let obligation = Obligation::new( self.tcx(), - param_env, cause.clone(), - trait_def_id, - recursion_depth, - [normalized_ty], + param_env, + self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]), ); - obligations.push(placeholder_obligation); + obligations.push(obligation); obligations }) .collect() @@ -2534,7 +2509,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&cause, obligation.param_env) - .eq(placeholder_obligation_trait_ref, impl_trait_ref) + .eq(DefineOpaqueTypes::No, placeholder_obligation_trait_ref, impl_trait_ref) .map_err(|e| { debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx())) })?; @@ -2584,7 +2559,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) + .sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| ()) } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index fcfb60b2603..8546bbe52dc 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -10,6 +10,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html pub mod specialization_graph; +use rustc_infer::infer::DefineOpaqueTypes; use specialization_graph::GraphExt; use crate::errors::NegativePositiveConflict; @@ -21,7 +22,7 @@ use crate::traits::{ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{error_code, DelayDm, Diagnostic}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt}; +use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; @@ -193,7 +194,7 @@ fn fulfill_implication<'tcx>( // do the impls unify? If not, no specialization. let Ok(InferOk { obligations: more_obligations, .. }) = - infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait, target_trait) + infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait) else { debug!( "fulfill_implication: {:?} does not unify with {:?}", @@ -349,6 +350,10 @@ fn report_conflicting_impls<'tcx>( impl_span: Span, err: &mut Diagnostic, ) { + if (overlap.trait_ref, overlap.self_ty).references_error() { + err.downgrade_to_delayed_bug(); + } + match tcx.span_of_impl(overlap.with_impl) { Ok(span) => { err.span_label(span, "first implementation here"); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index cd665d9471d..11eb968a415 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -3,7 +3,7 @@ use super::OverlapError; use crate::traits; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; -use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; +use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; pub use rustc_middle::traits::specialization_graph::*; @@ -49,12 +49,9 @@ impl<'tcx> ChildrenExt<'tcx> for Children { /// Insert an impl into this set of children without comparing to any existing impls. fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder(); - if let Some(st) = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(st) = + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey) + { debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); self.non_blanket_impls.entry(st).or_default().push(impl_def_id) } else { @@ -69,12 +66,9 @@ impl<'tcx> ChildrenExt<'tcx> for Children { fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder(); let vec: &mut Vec<DefId>; - if let Some(st) = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(st) = + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey) + { debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); vec = self.non_blanket_impls.get_mut(&st).unwrap(); } else { @@ -310,12 +304,8 @@ impl<'tcx> GraphExt<'tcx> for Graph { let mut parent = trait_def_id; let mut last_lint = None; - let simplified = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ); + let simplified = + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey); // Descend the specialization tree, where `parent` is the current parent node. loop { diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index bcf63d5a6f6..00c9a352258 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,15 +1,14 @@ -use rustc_errors::Diagnostic; -use rustc_span::Span; -use smallvec::SmallVec; - +use super::NormalizeExt; +use super::{ObligationCause, PredicateObligation, SelectionContext}; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Diagnostic; use rustc_hir::def_id::DefId; +use rustc_infer::infer::InferOk; +use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{GenericArg, SubstsRef}; +use rustc_span::Span; +use smallvec::SmallVec; -use super::NormalizeExt; -use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext}; -use rustc_infer::infer::InferOk; pub use rustc_infer::traits::{self, util::*}; /////////////////////////////////////////////////////////////////////////// @@ -201,6 +200,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) { let subject = selcx.tcx().bound_impl_subject(impl_def_id); let subject = subject.subst(selcx.tcx(), impl_substs); + let InferOk { value: subject, obligations: normalization_obligations1 } = selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject); @@ -218,33 +218,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( (subject, impl_obligations) } -pub fn predicate_for_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - recursion_depth: usize, -) -> PredicateObligation<'tcx> { - Obligation { - cause, - param_env, - recursion_depth, - predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), - } -} - -pub fn predicate_for_trait_def<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, -) -> PredicateObligation<'tcx> { - let trait_ref = tcx.mk_trait_ref(trait_def_id, params); - predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth) -} - /// Casts a trait reference into a reference to one of its super /// traits; returns `None` if `target_trait_def_id` is not a /// supertrait. diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d498af359c5..ec5bd982a3c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -191,8 +191,8 @@ pub fn predicate_obligations<'tcx>( ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`") + ty::PredicateKind::AliasRelate(..) => { + bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`") } } @@ -936,7 +936,7 @@ pub(crate) fn required_region_bounds<'tcx>( | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( ref t, diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 60e22d1001c..0e9bccba8d4 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -119,7 +119,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' }, ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) @@ -215,7 +215,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi // some of these in terms of chalk operations. ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::Ambiguous @@ -652,7 +652,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) @@ -787,7 +787,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index ddd4ca1436c..f5bba14d2fb 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -86,7 +86,7 @@ fn compute_implied_outlives_bounds<'tcx>( if obligation.predicate.has_non_region_infer() { match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::AliasEq(..) => { + | ty::PredicateKind::AliasRelate(..) => { ocx.register_obligation(obligation.clone()); } _ => {} @@ -110,7 +110,7 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} // We need to search through *all* WellFormed predicates diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index f0597f19225..126a494f34f 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -61,7 +61,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 35c9f95eb03..ee5a7909ba3 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -539,7 +539,7 @@ fn make_thin_self_ptr<'tcx>( // get a built-in pointer type let mut fat_pointer_layout = layout; 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() + && !fat_pointer_layout.ty.is_ref() { for i in 0..fat_pointer_layout.fields.count() { let field_layout = fat_pointer_layout.field(cx, i); diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index a2816124538..bf0bc202852 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -11,20 +11,20 @@ pub fn provide(providers: &mut ty::query::Providers) { associated_item, associated_item_def_ids, associated_items, - associated_items_for_impl_trait_in_trait, - associated_item_for_impl_trait_in_trait, + associated_types_for_impl_traits_in_associated_fn, + associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers }; } -fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { - let item = tcx.hir().expect_item(def_id.expect_local()); +fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { + let item = tcx.hir().expect_item(def_id); match item.kind { hir::ItemKind::Trait(.., ref trait_item_refs) => { if tcx.lower_impl_trait_in_trait_to_assoc_ty() { // We collect RPITITs for each trait method's return type and create a - // corresponding associated item using associated_items_for_impl_trait_in_trait + // corresponding associated item using associated_types_for_impl_traits_in_associated_fn // query. tcx.arena.alloc_from_iter( trait_item_refs @@ -39,7 +39,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { .flat_map(|trait_item_ref| { let trait_fn_def_id = trait_item_ref.id.owner_id.def_id.to_def_id(); - tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id) + tcx.associated_types_for_impl_traits_in_associated_fn( + trait_fn_def_id, + ) }) .map(|def_id| *def_id), ), @@ -56,7 +58,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { if tcx.lower_impl_trait_in_trait_to_assoc_ty() { // We collect RPITITs for each trait method's return type, on the impl side too and // create a corresponding associated item using - // associated_items_for_impl_trait_in_trait query. + // associated_types_for_impl_traits_in_associated_fn query. tcx.arena.alloc_from_iter( impl_ .items @@ -72,7 +74,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { .flat_map(|impl_item_ref| { let impl_fn_def_id = impl_item_ref.id.owner_id.def_id.to_def_id(); - tcx.associated_items_for_impl_trait_in_trait(impl_fn_def_id) + tcx.associated_types_for_impl_traits_in_associated_fn( + impl_fn_def_id, + ) }) .map(|def_id| *def_id) })), @@ -103,27 +107,26 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> .collect() } -fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { - let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); +fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { + let id = tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(id); let parent_item = tcx.hir().expect_item(parent_def_id.def_id); match parent_item.kind { hir::ItemKind::Impl(ref impl_) => { - if let Some(impl_item_ref) = - impl_.items.iter().find(|i| i.id.owner_id.to_def_id() == def_id) + if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id) { let assoc_item = associated_item_from_impl_item_ref(impl_item_ref); - debug_assert_eq!(assoc_item.def_id, def_id); + debug_assert_eq!(assoc_item.def_id.expect_local(), def_id); return assoc_item; } } hir::ItemKind::Trait(.., ref trait_item_refs) => { if let Some(trait_item_ref) = - trait_item_refs.iter().find(|i| i.id.owner_id.to_def_id() == def_id) + trait_item_refs.iter().find(|i| i.id.owner_id.def_id == def_id) { let assoc_item = associated_item_from_trait_item_ref(trait_item_ref); - debug_assert_eq!(assoc_item.def_id, def_id); + debug_assert_eq!(assoc_item.def_id.expect_local(), def_id); return assoc_item; } } @@ -176,14 +179,20 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A } } -/// Given an `fn_def_id` of a trait or of an impl that implements a given trait: -/// if `fn_def_id` is the def id of a function defined inside a trait, then it creates and returns -/// the associated items that correspond to each impl trait in return position for that trait. -/// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it -/// creates and returns the associated items that correspond to each impl trait in return position -/// of the implemented trait. -fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -> &'_ [DefId] { - let parent_def_id = tcx.parent(fn_def_id); +/// Given an `fn_def_id` of a trait or a trait implementation: +/// +/// if `fn_def_id` is a function defined inside a trait, then it synthesizes +/// a new def id corresponding to a new associated type for each return- +/// position `impl Trait` in the signature. +/// +/// if `fn_def_id` is a function inside of an impl, then for each synthetic +/// associated type generated for the corresponding trait function described +/// above, synthesize a corresponding associated type in the impl. +fn associated_types_for_impl_traits_in_associated_fn( + tcx: TyCtxt<'_>, + fn_def_id: LocalDefId, +) -> &'_ [DefId] { + let parent_def_id = tcx.local_parent(fn_def_id); match tcx.def_kind(parent_def_id) { DefKind::Trait => { @@ -202,11 +211,11 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) - let mut visitor = RPITVisitor { rpits: Vec::new() }; - if let Some(output) = tcx.hir().get_fn_output(fn_def_id.expect_local()) { + if let Some(output) = tcx.hir().get_fn_output(fn_def_id) { visitor.visit_fn_ret_ty(output); tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| { - tcx.associated_item_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id() + tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id() })) } else { &[] @@ -217,12 +226,12 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) - let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { return &[] }; tcx.arena.alloc_from_iter( - tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id).iter().map( + tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map( move |trait_assoc_def_id| { - impl_associated_item_for_impl_trait_in_trait( + associated_type_for_impl_trait_in_impl( tcx, trait_assoc_def_id.expect_local(), - fn_def_id.expect_local(), + fn_def_id, ) .to_def_id() }, @@ -231,26 +240,30 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) - } def_kind => bug!( - "associated_items_for_impl_trait_in_trait: {:?} should be Trait or Impl but is {:?}", + "associated_types_for_impl_traits_in_associated_fn: {:?} should be Trait or Impl but is {:?}", parent_def_id, def_kind ), } } -/// Given an `opaque_ty_def_id` corresponding to an impl trait in trait, create and return the -/// corresponding associated item. -fn associated_item_for_impl_trait_in_trait( +/// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated +/// function from a trait, synthesize an associated type for that `impl Trait` +/// that inherits properties that we infer from the method and the opaque type. +fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, ) -> LocalDefId { - let fn_def_id = tcx.impl_trait_in_trait_parent(opaque_ty_def_id.to_def_id()); - let trait_def_id = tcx.parent(fn_def_id); + let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = + tcx.hir().expect_item(opaque_ty_def_id).expect_opaque_ty().origin + else { + bug!("expected opaque for {opaque_ty_def_id:?}"); + }; + let trait_def_id = tcx.local_parent(fn_def_id); assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); let span = tcx.def_span(opaque_ty_def_id); - let trait_assoc_ty = - tcx.at(span).create_def(trait_def_id.expect_local(), DefPathData::ImplTraitAssocTy); + let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, DefPathData::ImplTraitAssocTy); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -272,7 +285,7 @@ fn associated_item_for_impl_trait_in_trait( container: ty::TraitContainer, fn_has_self_parameter: false, opt_rpitit_info: Some(ImplTraitInTraitData::Trait { - fn_def_id, + fn_def_id: fn_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(), }), }); @@ -286,15 +299,46 @@ fn associated_item_for_impl_trait_in_trait( // Copy type_of of the opaque. trait_assoc_ty.type_of(ty::EarlyBinder(tcx.mk_opaque( opaque_ty_def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, opaque_ty_def_id.to_def_id()), + InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), ))); - // Copy generics_of of the opaque. - trait_assoc_ty.generics_of(tcx.generics_of(opaque_ty_def_id).clone()); + trait_assoc_ty.is_type_alias_impl_trait(false); + + // Copy generics_of of the opaque type item but the trait is the parent. + trait_assoc_ty.generics_of({ + let opaque_ty_generics = tcx.generics_of(opaque_ty_def_id); + let opaque_ty_parent_count = opaque_ty_generics.parent_count; + let mut params = opaque_ty_generics.params.clone(); + + let parent_generics = tcx.generics_of(trait_def_id); + let parent_count = parent_generics.parent_count + parent_generics.params.len(); + + let mut trait_fn_params = tcx.generics_of(fn_def_id).params.clone(); + + for param in &mut params { + param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32 + - opaque_ty_parent_count as u32; + } + + trait_fn_params.extend(params); + params = trait_fn_params; + + let param_def_id_to_index = + params.iter().map(|param| (param.def_id, param.index)).collect(); + + ty::Generics { + parent: Some(trait_def_id.to_def_id()), + parent_count, + params, + param_def_id_to_index, + has_self: false, + has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, + } + }); // There are no predicates for the synthesized associated type. trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates { - parent: Some(trait_def_id), + parent: Some(trait_def_id.to_def_id()), predicates: &[], }); @@ -304,16 +348,17 @@ fn associated_item_for_impl_trait_in_trait( local_def_id } -/// Given an `trait_assoc_def_id` that corresponds to a previously synthesized impl trait in trait -/// into an associated type and an `impl_def_id` corresponding to an impl block, create and return -/// the corresponding associated item inside the impl block. -fn impl_associated_item_for_impl_trait_in_trait( +/// Given an `trait_assoc_def_id` corresponding to an associated item synthesized +/// from an `impl Trait` in an associated function from a trait, and an +/// `impl_fn_def_id` that represents an implementation of the associated function +/// that the `impl Trait` comes from, synthesize an associated type for that `impl Trait` +/// that inherits properties that we infer from the method and the associated type. +fn associated_type_for_impl_trait_in_impl( tcx: TyCtxt<'_>, trait_assoc_def_id: LocalDefId, impl_fn_def_id: LocalDefId, ) -> LocalDefId { let impl_local_def_id = tcx.local_parent(impl_fn_def_id); - let impl_def_id = impl_local_def_id.to_def_id(); // FIXME fix the span, we probably want the def_id of the return type of the function let span = tcx.def_span(impl_fn_def_id); @@ -341,10 +386,6 @@ fn impl_associated_item_for_impl_trait_in_trait( opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), }); - // Copy param_env of the containing function. The synthesized associated type doesn't have - // extra predicates to assume. - impl_assoc_ty.param_env(tcx.param_env(impl_fn_def_id)); - // Copy visility of the containing function. impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id)); @@ -352,29 +393,25 @@ fn impl_associated_item_for_impl_trait_in_trait( impl_assoc_ty.impl_defaultness(tcx.impl_defaultness(impl_fn_def_id)); // Copy generics_of the trait's associated item but the impl as the parent. + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) resolves to the trait instead of the impl + // generics. impl_assoc_ty.generics_of({ let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id); let trait_assoc_parent_count = trait_assoc_generics.parent_count; let mut params = trait_assoc_generics.params.clone(); - let parent_generics = tcx.generics_of(impl_def_id); + let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id()); let parent_count = parent_generics.parent_count + parent_generics.params.len(); - let mut impl_fn_params = tcx.generics_of(impl_fn_def_id).params.clone(); - for param in &mut params { - param.index = param.index + parent_count as u32 + impl_fn_params.len() as u32 - - trait_assoc_parent_count as u32; + param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32; } - impl_fn_params.extend(params); - params = impl_fn_params; - let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { - parent: Some(impl_def_id), + parent: Some(impl_local_def_id.to_def_id()), parent_count, params, param_def_id_to_index, @@ -385,7 +422,7 @@ fn impl_associated_item_for_impl_trait_in_trait( // There are no predicates for the synthesized associated type. impl_assoc_ty.explicit_predicates_of(ty::GenericPredicates { - parent: Some(impl_def_id), + parent: Some(impl_local_def_id.to_def_id()), predicates: &[], }); diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index d3169b6d962..3b1abdcb24f 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -3,7 +3,6 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { @@ -30,7 +29,7 @@ fn is_item_raw<'tcx>( let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(item, None); let infcx = tcx.infer_ctxt().build(); - traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id, DUMMY_SP) + traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) } pub(crate) fn provide(providers: &mut ty::query::Providers) { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index f2635271609..4d0fd260de2 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -425,7 +425,6 @@ pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { destructure_const, thir_abstract_const: |tcx, def_id| { - let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.thir_abstract_const_of_const_arg(def) } else { diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 591017eecd2..26d6deab883 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -4,7 +4,7 @@ use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::LocalDefId; pub fn provide(providers: &mut Providers) { *providers = @@ -85,7 +85,7 @@ fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representab Representability::Representable } -fn params_in_repr(tcx: TyCtxt<'_>, def_id: DefId) -> BitSet<u32> { +fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> BitSet<u32> { let adt_def = tcx.adt_def(def_id); let generics = tcx.generics_of(def_id); let mut params_in_repr = BitSet::new_empty(generics.params.len()); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index d41bf603983..50aeb7f440f 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -7,7 +7,8 @@ use rustc_middle::ty::{ TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_session::config::TraitSolver; -use rustc_span::def_id::{DefId, CRATE_DEF_ID}; +use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; fn sized_constraint_for_ty<'tcx>( @@ -76,8 +77,8 @@ fn sized_constraint_for_ty<'tcx>( result } -fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness { - match tcx.hir().get_by_def_id(def_id.expect_local()) { +fn impl_defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { + match tcx.hir().get_by_def_id(def_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness, hir::Node::ImplItem(hir::ImplItem { defaultness, .. }) | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness, @@ -117,16 +118,24 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] { /// See `ParamEnv` struct definition for details. fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { - // When computing the param_env of an RPITIT, copy param_env of the containing function. The - // synthesized associated type doesn't have extra predicates to assume. - if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) { - return tcx.param_env(fn_def_id); - } - // Compute the bounds on Self and the type parameters. let ty::InstantiatedPredicates { mut predicates, .. } = tcx.predicates_of(def_id).instantiate_identity(tcx); + // When computing the param_env of an RPITIT, use predicates of the containing function, + // *except* for the additional assumption that the RPITIT normalizes to the trait method's + // default opaque type. This is needed to properly check the item bounds of the assoc + // type hold (`check_type_bounds`), since that method already installs a similar projection + // bound, so they will conflict. + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): I don't like this, we should + // at least be making sure that the generics in RPITITs and their parent fn don't + // get out of alignment, or else we do actually need to substitute these predicates. + if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) + | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) + { + predicates = tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates; + } + // Finally, we have to normalize the bounds in the environment, in // case they contain any associated type projections. This process // can yield errors if the put in illegal associated types, like @@ -160,7 +169,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { } let local_did = def_id.as_local(); - let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)); + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This isn't correct for + // RPITITs in const trait fn. + let hir_id = local_did.and_then(|def_id| tcx.opt_local_def_id_to_hir_id(def_id)); // FIXME(consts): This is not exactly in line with the constness query. let constness = match hir_id { @@ -267,33 +278,53 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { } fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { - if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() - && self.tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder - && self.tcx.impl_trait_in_trait_parent(alias_ty.def_id) == self.fn_def_id - && self.seen.insert(alias_ty.def_id) + if let ty::Alias(ty::Projection, unshifted_alias_ty) = *ty.kind() + && self.tcx.is_impl_trait_in_trait(unshifted_alias_ty.def_id) + && self.tcx.impl_trait_in_trait_parent_fn(unshifted_alias_ty.def_id) == self.fn_def_id + && self.seen.insert(unshifted_alias_ty.def_id) { // We have entered some binders as we've walked into the // bounds of the RPITIT. Shift these binders back out when // constructing the top-level projection predicate. - let alias_ty = self.tcx.fold_regions(alias_ty, |re, _| { + let shifted_alias_ty = self.tcx.fold_regions(unshifted_alias_ty, |re, depth| { if let ty::ReLateBound(index, bv) = re.kind() { + if depth != ty::INNERMOST { + return self.tcx.mk_re_error_with_message( + DUMMY_SP, + "we shouldn't walk non-predicate binders with `impl Trait`...", + ); + } self.tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv) } else { re } }); + + // If we're lowering to associated item, install the opaque type which is just + // the `type_of` of the trait's associated item. If we're using the old lowering + // strategy, then just reinterpret the associated type like an opaque :^) + let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { + self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs) + } else { + self.tcx.mk_alias(ty::Opaque, shifted_alias_ty) + }; + self.predicates.push( ty::Binder::bind_with_vars( - ty::ProjectionPredicate { - projection_ty: alias_ty, - term: self.tcx.mk_alias(ty::Opaque, alias_ty).into(), - }, + ty::ProjectionPredicate { projection_ty: shifted_alias_ty, term: default_ty.into() }, self.bound_vars, ) .to_predicate(self.tcx), ); - for bound in self.tcx.item_bounds(alias_ty.def_id).subst_iter(self.tcx, alias_ty.substs) + // We walk the *un-shifted* alias ty, because we're tracking the de bruijn + // binder depth, and if we were to walk `shifted_alias_ty` instead, we'd + // have to reset `self.depth` back to `ty::INNERMOST` or something. It's + // easier to just do this. + for bound in self + .tcx + .item_bounds(unshifted_alias_ty.def_id) + .subst_iter(self.tcx, unshifted_alias_ty.substs) { bound.visit_with(self); } @@ -485,8 +516,8 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<EarlyBinder<Ty<' } /// Check if a function is async. -fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { - let node = tcx.hir().get_by_def_id(def_id.expect_local()); +fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::IsAsync { + let node = tcx.hir().get_by_def_id(def_id); node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness) } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 5a991e03dee..8b23fbc7583 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -432,6 +432,17 @@ impl IntTy { _ => *self, } } + + pub fn to_unsigned(self) -> UintTy { + match self { + IntTy::Isize => UintTy::Usize, + IntTy::I8 => UintTy::U8, + IntTy::I16 => UintTy::U16, + IntTy::I32 => UintTy::U32, + IntTy::I64 => UintTy::U64, + IntTy::I128 => UintTy::U128, + } + } } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] @@ -479,6 +490,17 @@ impl UintTy { _ => *self, } } + + pub fn to_signed(self) -> IntTy { + match self { + UintTy::Usize => IntTy::Isize, + UintTy::U8 => IntTy::I8, + UintTy::U16 => IntTy::I16, + UintTy::U32 => IntTy::I32, + UintTy::U64 => IntTy::I64, + UintTy::U128 => IntTy::I128, + } + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] diff --git a/config.example.toml b/config.example.toml index 7ae46203f97..32eab76b369 100644 --- a/config.example.toml +++ b/config.example.toml @@ -806,3 +806,9 @@ changelog-seen = 2 # # This list must be non-empty. #compression-formats = ["gz", "xz"] + +# How much time should be spent compressing the tarballs. The better the +# compression profile, the longer compression will take. +# +# Available options: fast, balanced, best +#compression-profile = "fast" diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 7552f2fc04c..c7d0144de30 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -13,7 +13,6 @@ pub mod set; mod set_val; mod split; -#[doc(hidden)] trait Recover<Q: ?Sized> { type Key; diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 4ddb2119252..4de30d40825 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1,6 +1,3 @@ -// This is pretty much entirely stolen from TreeSet, since BTreeMap has an identical interface -// to TreeMap - use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering::{self, Equal, Greater, Less}; @@ -18,8 +15,6 @@ use super::Recover; use crate::alloc::{Allocator, Global}; -// FIXME(conventions): implement bounded iterators - /// An ordered set based on a B-Tree. /// /// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index e9cc3875f68..5469261ef56 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -87,7 +87,7 @@ #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] -#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))] +#![warn(multiple_supertrait_upcastable)] // // Library features: #![feature(alloc_layout_extra)] @@ -195,7 +195,7 @@ #![feature(c_unwind)] #![feature(with_negative_coherence)] #![cfg_attr(test, feature(panic_update_hook))] -#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))] +#![feature(multiple_supertrait_upcastable)] // // Rustdoc features: #![feature(doc_cfg)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 77b0447b345..1e9cf404f77 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -692,10 +692,10 @@ impl<T> Rc<T> { /// it is guaranteed that exactly one of the calls returns the inner value. /// This means in particular that the inner value is not dropped. /// - /// This is equivalent to `Rc::try_unwrap(...).ok()`. (Note that these are not equivalent for - /// `Arc`, due to race conditions that do not apply to `Rc`.) + /// This is equivalent to `Rc::try_unwrap(this).ok()`. (Note that these are not equivalent for + /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`.) #[inline] - #[unstable(feature = "rc_into_inner", issue = "106894")] + #[stable(feature = "rc_into_inner", since = "CURRENT_RUSTC_VERSION")] pub fn into_inner(this: Self) -> Option<T> { Rc::try_unwrap(this).ok() } @@ -1738,11 +1738,11 @@ impl<T: ?Sized + PartialEq> PartialEq for Rc<T> { /// Inequality for two `Rc`s. /// - /// Two `Rc`s are unequal if their inner values are unequal. + /// Two `Rc`s are not equal if their inner values are not equal. /// /// If `T` also implements `Eq` (implying reflexivity of equality), /// two `Rc`s that point to the same allocation are - /// never unequal. + /// always equal. /// /// # Examples /// diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index f37573c6f27..150924851d2 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -662,20 +662,17 @@ impl<T> Arc<T> { /// /// This will succeed even if there are outstanding weak references. /// - // FIXME: when `Arc::into_inner` is stabilized, add this paragraph: - /* /// It is strongly recommended to use [`Arc::into_inner`] instead if you don't /// want to keep the `Arc` in the [`Err`] case. /// Immediately dropping the [`Err`] payload, like in the expression /// `Arc::try_unwrap(this).ok()`, can still cause the strong count to /// drop to zero and the inner value of the `Arc` to be dropped: - /// For instance if two threads execute this expression in parallel, then + /// For instance if two threads each execute this expression in parallel, then /// there is a race condition. The threads could first both check whether they /// have the last clone of their `Arc` via `Arc::try_unwrap`, and then /// both drop their `Arc` in the call to [`ok`][`Result::ok`], /// taking the strong count from two down to zero. /// - */ /// # Examples /// /// ``` @@ -719,20 +716,13 @@ impl<T> Arc<T> { /// This means in particular that the inner value is not dropped. /// /// The similar expression `Arc::try_unwrap(this).ok()` does not - /// offer such a guarantee. See the last example below. - // - // FIXME: when `Arc::into_inner` is stabilized, add this to end - // of the previous sentence: - /* + /// offer such a guarantee. See the last example below /// and the documentation of [`Arc::try_unwrap`]. - */ /// /// # Examples /// /// Minimal example demonstrating the guarantee that `Arc::into_inner` gives. /// ``` - /// #![feature(arc_into_inner)] - /// /// use std::sync::Arc; /// /// let x = Arc::new(3); @@ -756,8 +746,6 @@ impl<T> Arc<T> { /// /// A more practical example demonstrating the need for `Arc::into_inner`: /// ``` - /// #![feature(arc_into_inner)] - /// /// use std::sync::Arc; /// /// // Definition of a simple singly linked list using `Arc`: @@ -807,13 +795,8 @@ impl<T> Arc<T> { /// x_thread.join().unwrap(); /// y_thread.join().unwrap(); /// ``` - - // FIXME: when `Arc::into_inner` is stabilized, adjust above documentation - // and the documentation of `Arc::try_unwrap` according to the `FIXME`s. Also - // open an issue on rust-lang/rust-clippy, asking for a lint against - // `Arc::try_unwrap(...).ok()`. #[inline] - #[unstable(feature = "arc_into_inner", issue = "106894")] + #[stable(feature = "arc_into_inner", since = "CURRENT_RUSTC_VERSION")] pub fn into_inner(this: Self) -> Option<T> { // Make sure that the ordinary `Drop` implementation isn’t called as well let mut this = mem::ManuallyDrop::new(this); @@ -2475,10 +2458,10 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> { /// Inequality for two `Arc`s. /// - /// Two `Arc`s are unequal if their inner values are unequal. + /// Two `Arc`s are not equal if their inner values are not equal. /// /// If `T` also implements `Eq` (implying reflexivity of equality), - /// two `Arc`s that point to the same value are never unequal. + /// two `Arc`s that point to the same value are always equal. /// /// # Examples /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f2aa30f18fc..9f0111db452 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -59,7 +59,6 @@ use core::cmp::Ordering; use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; -use core::intrinsics::assume; use core::iter; #[cfg(not(no_global_oom_handling))] use core::iter::FromIterator; @@ -1240,11 +1239,7 @@ impl<T, A: Allocator> Vec<T, A> { pub fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through // `deref`, which creates an intermediate reference. - let ptr = self.buf.ptr(); - unsafe { - assume(!ptr.is_null()); - } - ptr + self.buf.ptr() } /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling @@ -1277,11 +1272,7 @@ impl<T, A: Allocator> Vec<T, A> { pub fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through // `deref_mut`, which creates an intermediate reference. - let ptr = self.buf.ptr(); - unsafe { - assume(!ptr.is_null()); - } - ptr + self.buf.ptr() } /// Returns a reference to the underlying allocator. diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 4d182be02c9..c1dbbde08b6 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1499,13 +1499,25 @@ fn test_split_whitespace() { #[test] fn test_lines() { - let data = "\nMäry häd ä little lämb\n\r\nLittle lämb\n"; - let lines: Vec<&str> = data.lines().collect(); - assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]); - - let data = "\r\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n - let lines: Vec<&str> = data.lines().collect(); - assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]); + fn t(data: &str, expected: &[&str]) { + let lines: Vec<&str> = data.lines().collect(); + assert_eq!(lines, expected); + } + t("", &[]); + t("\n", &[""]); + t("\n2nd", &["", "2nd"]); + t("\r\n", &[""]); + t("bare\r", &["bare\r"]); + t("bare\rcr", &["bare\rcr"]); + t("Text\n\r", &["Text", "\r"]); + t( + "\nMäry häd ä little lämb\n\r\nLittle lämb\n", + &["", "Märy häd ä little lämb", "", "Little lämb"], + ); + t( + "\r\nMäry häd ä little lämb\n\nLittle lämb", + &["", "Märy häd ä little lämb", "", "Little lämb"], + ); } #[test] diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 571bc4bcfd1..11cb0827578 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -28,7 +28,7 @@ use crate::fmt::{Debug, Display}; #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Error")] #[rustc_has_incoherent_inherent_impls] -#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))] +#[allow(multiple_supertrait_upcastable)] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. /// @@ -489,7 +489,7 @@ impl Error for crate::char::CharTryFromError { #[stable(feature = "duration_checked_float", since = "1.66.0")] impl Error for crate::time::TryFromFloatSecsError {} -#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] impl Error for crate::ffi::FromBytesUntilNulError {} #[unstable(feature = "get_many_mut", issue = "104642")] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 87f077325f8..fe8abdf7fad 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -153,10 +153,10 @@ impl Error for FromBytesWithNulError { /// This error is created by the [`CStr::from_bytes_until_nul`] method. /// #[derive(Clone, PartialEq, Eq, Debug)] -#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub struct FromBytesUntilNulError(()); -#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] impl fmt::Display for FromBytesUntilNulError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "data provided does not contain a nul") @@ -324,8 +324,8 @@ impl CStr { /// ``` /// #[rustc_allow_const_fn_unstable(const_slice_index)] - #[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] + #[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c9821bf8109..fcda097f01f 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -267,7 +267,7 @@ extern "C" { /// family of functions. It contains a function to format the given value. At /// compile time it is ensured that the function and the value have the correct /// types, and then this struct is used to canonicalize arguments to one type. -#[cfg_attr(not(bootstrap), lang = "format_argument")] +#[lang = "format_argument"] #[derive(Copy, Clone)] #[allow(missing_debug_implementations)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -280,7 +280,7 @@ pub struct ArgumentV1<'a> { /// This struct represents the unsafety of constructing an `Arguments`. /// It exists, rather than an unsafe function, in order to simplify the expansion /// of `format_args!(..)` and reduce the scope of the `unsafe` block. -#[cfg_attr(not(bootstrap), lang = "format_unsafe_arg")] +#[lang = "format_unsafe_arg"] #[allow(missing_debug_implementations)] #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -392,8 +392,31 @@ enum FlagV1 { } impl<'a> Arguments<'a> { + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", issue = "none")] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + pub const fn new_const(pieces: &'a [&'static str]) -> Self { + if pieces.len() > 1 { + panic!("invalid args"); + } + Arguments { pieces, fmt: None, args: &[] } + } + /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. + #[cfg(not(bootstrap))] + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { + if pieces.len() < args.len() || pieces.len() > args.len() + 1 { + panic!("invalid args"); + } + Arguments { pieces, fmt: None, args } + } + + #[cfg(bootstrap)] #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -417,8 +440,7 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const fn new_v1_formatted( + pub fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument], @@ -475,7 +497,7 @@ impl<'a> Arguments<'a> { /// ``` /// /// [`format()`]: ../../std/fmt/fn.format.html -#[cfg_attr(not(bootstrap), lang = "format_arguments")] +#[lang = "format_arguments"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone)] pub struct Arguments<'a> { diff --git a/library/core/src/fmt/rt/v1.rs b/library/core/src/fmt/rt/v1.rs index 11a50951a75..6d70796f707 100644 --- a/library/core/src/fmt/rt/v1.rs +++ b/library/core/src/fmt/rt/v1.rs @@ -5,7 +5,7 @@ //! these can be statically allocated and are slightly optimized for the runtime #![allow(missing_debug_implementations)] -#[cfg_attr(not(bootstrap), lang = "format_placeholder")] +#[lang = "format_placeholder"] #[derive(Copy, Clone)] // FIXME: Rename this to Placeholder pub struct Argument { @@ -37,7 +37,7 @@ impl Argument { } /// Possible alignments that can be requested as part of a formatting directive. -#[cfg_attr(not(bootstrap), lang = "format_alignment")] +#[lang = "format_alignment"] #[derive(Copy, Clone, PartialEq, Eq)] pub enum Alignment { /// Indication that contents should be left-aligned. @@ -51,7 +51,7 @@ pub enum Alignment { } /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. -#[cfg_attr(not(bootstrap), lang = "format_count")] +#[lang = "format_count"] #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 71a0d1825ef..4e7bae7bcb0 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -158,7 +158,7 @@ mod sip; /// /// Implementations of `hash` should ensure that the data they /// pass to the `Hasher` are prefix-free. That is, -/// unequal values should cause two different sequences of values to be written, +/// values which are not equal should cause two different sequences of values to be written, /// and neither of the two sequences should be a prefix of the other. /// /// For example, the standard implementation of [`Hash` for `&str`][impl] passes an extra @@ -834,7 +834,7 @@ mod impls { #[inline] fn hash_slice<H: ~const Hasher>(data: &[$ty], state: &mut H) { - let newlen = data.len() * mem::size_of::<$ty>(); + let newlen = mem::size_of_val(data); let ptr = data.as_ptr() as *const u8; // SAFETY: `ptr` is valid and aligned, as this macro is only used // for numeric primitives which have no padding. The new slice only diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index ee8846675ce..7482b8b0862 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2214,6 +2214,12 @@ extern "rust-intrinsic" { where G: FnOnce<ARG, Output = RET>, F: FnOnce<ARG, Output = RET>; + + #[cfg(not(bootstrap))] + /// This method creates a pointer to any `Some` value. If the argument is + /// `None`, an invalid within-bounds pointer (that is still acceptable for + /// constructing an empty slice) is returned. + pub fn option_payload_ptr<T>(arg: *const Option<T>) -> *const T; } // Some functions are defined here because they accidentally got made diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index d2d9771bdce..6690c1a76d5 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -8,7 +8,7 @@ //! //! The documentation for this module describes how to use this feature. If you are interested in //! hacking on the implementation, most of that documentation lives at -//! `rustc_mir_building/src/build/custom/mod.rs`. +//! `rustc_mir_build/src/build/custom/mod.rs`. //! //! Typical usage will look like this: //! @@ -49,6 +49,8 @@ //! //! The input to the [`mir!`] macro is: //! +//! - An optional return type annotation in the form of `type RET = ...;`. This may be required +//! if the compiler cannot infer the type of RET. //! - A possibly empty list of local declarations. Locals can also be declared inline on //! assignments via `let`. Type inference generally works. Shadowing does not. //! - A list of basic blocks. The first of these is the start block and is where execution begins. @@ -124,6 +126,18 @@ //! } //! ) //! } +//! +//! #[custom_mir(dialect = "runtime", phase = "optimized")] +//! fn annotated_return_type() -> (i32, bool) { +//! mir!( +//! type RET = (i32, bool); +//! { +//! RET.0 = 1; +//! RET.1 = true; +//! Return() +//! } +//! ) +//! } //! ``` //! //! We can also set off compilation failures that happen in sufficiently late stages of the @@ -330,6 +344,14 @@ define!( fn Variant<T>(place: T, index: u32) -> () ); define!( + "mir_cast_transmute", + /// Emits a `CastKind::Transmute` cast. + /// + /// Needed to test the UB when `sizeof(T) != sizeof(U)`, which can't be + /// generated via the normal `mem::transmute`. + fn CastTransmute<T, U>(operand: T) -> U +); +define!( "mir_make_place", #[doc(hidden)] fn __internal_make_place<T>(place: T) -> *mut T @@ -342,6 +364,7 @@ define!( #[rustc_macro_transparency = "transparent"] pub macro mir { ( + $(type RET = $ret_ty:ty ;)? $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)* { @@ -362,7 +385,7 @@ pub macro mir { { // Now all locals #[allow(non_snake_case)] - let RET; + let RET $(: $ret_ty)?; $( let $local_decl $(: $local_decl_ty)? ; )* diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index ae00232c12c..de638552fa3 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -278,7 +278,7 @@ //! //! ``` //! # #![allow(unused_must_use)] -//! # #![cfg_attr(not(bootstrap), allow(map_unit_fn))] +//! # #![allow(map_unit_fn)] //! let v = vec![1, 2, 3, 4, 5]; //! v.iter().map(|x| println!("{x}")); //! ``` diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 78e27d73065..f19636fba5d 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,4 +1,5 @@ use crate::convert::TryFrom; +use crate::marker::Destruct; use crate::mem; use crate::ops::{self, Try}; @@ -20,7 +21,8 @@ unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usi /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] -pub trait Step: Clone + PartialOrd + Sized { +#[const_trait] +pub trait Step: ~const Clone + ~const PartialOrd + Sized { /// Returns the number of *successor* steps required to get from `start` to `end`. /// /// Returns `None` if the number of steps would overflow `usize` @@ -234,7 +236,8 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - impl Step for $u_narrower { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const Step for $u_narrower { step_identical_methods!(); #[inline] @@ -266,7 +269,8 @@ macro_rules! step_integer_impls { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - impl Step for $i_narrower { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const Step for $i_narrower { step_identical_methods!(); #[inline] @@ -330,7 +334,8 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - impl Step for $u_wider { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const Step for $u_wider { step_identical_methods!(); #[inline] @@ -355,7 +360,8 @@ macro_rules! step_integer_impls { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - impl Step for $i_wider { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const Step for $i_wider { step_identical_methods!(); #[inline] @@ -405,7 +411,8 @@ step_integer_impls! { } #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] -impl Step for char { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Step for char { #[inline] fn steps_between(&start: &char, &end: &char) -> Option<usize> { let start = start as u32; @@ -423,6 +430,7 @@ impl Step for char { } #[inline] + #[rustc_allow_const_fn_unstable(const_try)] fn forward_checked(start: char, count: usize) -> Option<char> { let start = start as u32; let mut res = Step::forward_checked(start, count)?; @@ -439,6 +447,7 @@ impl Step for char { } #[inline] + #[rustc_allow_const_fn_unstable(const_try)] fn backward_checked(start: char, count: usize) -> Option<char> { let start = start as u32; let mut res = Step::backward_checked(start, count)?; @@ -514,6 +523,7 @@ macro_rules! range_incl_exact_iter_impl { } /// Specialization implementations for `Range`. +#[const_trait] trait RangeIteratorImpl { type Item; @@ -528,7 +538,7 @@ trait RangeIteratorImpl { fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>; } -impl<A: Step> RangeIteratorImpl for ops::Range<A> { +impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A> { type Item = A; #[inline] @@ -614,7 +624,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> { } } -impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { +impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::Range<T> { #[inline] fn spec_next(&mut self) -> Option<T> { if self.start < self.end { @@ -702,7 +712,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: Step> Iterator for ops::Range<A> { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl<A: ~const Step + ~const Destruct> const Iterator for ops::Range<A> { type Item = A; #[inline] @@ -812,7 +823,8 @@ range_incl_exact_iter_impl! { } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: Step> DoubleEndedIterator for ops::Range<A> { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl<A: ~const Step + ~const Destruct> const DoubleEndedIterator for ops::Range<A> { #[inline] fn next_back(&mut self) -> Option<A> { self.spec_next_back() diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index e31669b3924..f9c7eb8f938 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -164,12 +164,13 @@ where /// element is encountered: /// /// ``` + /// let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) }; /// let v = vec![1, 2]; - /// let res: Result<i32, &'static str> = v.iter().map(|&x: &i32| - /// if x < 0 { Err("Negative element found") } - /// else { Ok(x) } - /// ).sum(); + /// let res: Result<i32, _> = v.iter().map(f).sum(); /// assert_eq!(res, Ok(3)); + /// let v = vec![1, -2]; + /// let res: Result<i32, _> = v.iter().map(f).sum(); + /// assert_eq!(res, Err("Negative element found")); /// ``` fn sum<I>(iter: I) -> Result<T, E> where @@ -187,6 +188,20 @@ where /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further /// elements are taken, and the [`Err`] is returned. Should no [`Err`] /// occur, the product of all elements is returned. + /// + /// # Examples + /// + /// This multiplies each number in a vector of strings, + /// if a string could not be parsed the operation returns `Err`: + /// + /// ``` + /// let nums = vec!["5", "10", "1", "2"]; + /// let total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product(); + /// assert_eq!(total, Ok(100)); + /// let nums = vec!["5", "10", "one", "2"]; + /// let total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product(); + /// assert!(total.is_err()); + /// ``` fn product<I>(iter: I) -> Result<T, E> where I: Iterator<Item = Result<U, E>>, @@ -213,6 +228,9 @@ where /// let words = vec!["have", "a", "great", "day"]; /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum(); /// assert_eq!(total, Some(5)); + /// let words = vec!["have", "a", "good", "day"]; + /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum(); + /// assert_eq!(total, None); /// ``` fn sum<I>(iter: I) -> Option<T> where @@ -230,6 +248,20 @@ where /// Takes each element in the [`Iterator`]: if it is a [`None`], no further /// elements are taken, and the [`None`] is returned. Should no [`None`] /// occur, the product of all elements is returned. + /// + /// # Examples + /// + /// This multiplies each number in a vector of strings, + /// if a string could not be parsed the operation returns `None`: + /// + /// ``` + /// let nums = vec!["5", "10", "1", "2"]; + /// let total: Option<usize> = nums.iter().map(|w| w.parse::<usize>().ok()).product(); + /// assert_eq!(total, Some(100)); + /// let nums = vec!["5", "10", "one", "2"]; + /// let total: Option<usize> = nums.iter().map(|w| w.parse::<usize>().ok()).product(); + /// assert_eq!(total, None); + /// ``` fn product<I>(iter: I) -> Option<T> where I: Iterator<Item = Option<U>>, diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index ed23873cdde..7a10dea500a 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,3 +1,4 @@ +use crate::marker::Destruct; use crate::ops::{ControlFlow, Try}; /// An iterator able to yield elements from both ends. @@ -37,6 +38,7 @@ use crate::ops::{ControlFlow, Try}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] +#[const_trait] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// @@ -131,7 +133,10 @@ pub trait DoubleEndedIterator: Iterator { /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> + where + Self::Item: ~const Destruct, + { for i in 0..n { self.next_back().ok_or(i)?; } @@ -181,6 +186,7 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_nth_back", since = "1.37.0")] + #[rustc_do_not_const_check] fn nth_back(&mut self, n: usize) -> Option<Self::Item> { self.advance_back_by(n).ok()?; self.next_back() @@ -218,6 +224,7 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] + #[rustc_do_not_const_check] fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where Self: Sized, @@ -289,6 +296,7 @@ pub trait DoubleEndedIterator: Iterator { #[doc(alias = "foldr")] #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] + #[rustc_do_not_const_check] fn rfold<B, F>(mut self, init: B, mut f: F) -> B where Self: Sized, @@ -344,6 +352,7 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfind", since = "1.27.0")] + #[rustc_do_not_const_check] fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item> where Self: Sized, diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index b8e7d0a68da..16c9f668b8e 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,5 +1,6 @@ use crate::array; use crate::cmp::{self, Ordering}; +use crate::marker::Destruct; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; @@ -69,7 +70,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} #[doc(notable_trait)] #[rustc_diagnostic_item = "Iterator"] #[must_use = "iterators are lazy and do nothing unless consumed"] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Iterator { /// The type of the elements being iterated over. #[rustc_diagnostic_item = "IteratorItem"] @@ -336,8 +337,10 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - #[rustc_do_not_const_check] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> Result<(), usize> + where + Self::Item: ~const Destruct, + { for i in 0..n { self.next().ok_or(i)?; } @@ -385,8 +388,10 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] - fn nth(&mut self, n: usize) -> Option<Self::Item> { + fn nth(&mut self, n: usize) -> Option<Self::Item> + where + Self::Item: ~const Destruct, + { self.advance_by(n).ok()?; self.next() } @@ -1998,7 +2003,7 @@ pub trait Iterator { /// a.iter().map(|&x| x * 2).collect_into(&mut vec); /// a.iter().map(|&x| x * 10).collect_into(&mut vec); /// - /// assert_eq!(vec![0, 1, 2, 4, 6, 10, 20, 30], vec); + /// assert_eq!(vec, vec![0, 1, 2, 4, 6, 10, 20, 30]); /// ``` /// /// `Vec` can have a manual set capacity to avoid reallocating it: @@ -2013,7 +2018,7 @@ pub trait Iterator { /// a.iter().map(|&x| x * 10).collect_into(&mut vec); /// /// assert_eq!(6, vec.capacity()); - /// println!("{:?}", vec); + /// assert_eq!(vec, vec![2, 4, 6, 10, 20, 30]); /// ``` /// /// The returned mutable reference can be used to continue the call chain: @@ -2027,12 +2032,12 @@ pub trait Iterator { /// let count = a.iter().collect_into(&mut vec).iter().count(); /// /// assert_eq!(count, vec.len()); - /// println!("Vec len is {}", count); + /// assert_eq!(vec, vec![1, 2, 3]); /// /// let count = a.iter().collect_into(&mut vec).iter().count(); /// /// assert_eq!(count, vec.len()); - /// println!("Vec len now is {}", count); + /// assert_eq!(vec, vec![1, 2, 3, 1, 2, 3]); /// ``` #[inline] #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")] @@ -3443,6 +3448,9 @@ pub trait Iterator { /// /// An empty iterator returns the zero value of the type. /// + /// `sum()` can be used to sum any type implementing [`Sum`][`core::iter::Sum`], + /// including [`Option`][`Option::sum`] and [`Result`][`Result::sum`]. + /// /// # Panics /// /// When calling `sum()` and a primitive integer type is being returned, this @@ -3473,6 +3481,9 @@ pub trait Iterator { /// /// An empty iterator returns the one value of the type. /// + /// `product()` can be used to multiply any type implementing [`Product`][`core::iter::Product`], + /// including [`Option`][`Option::product`] and [`Result`][`Result::product`]. + /// /// # Panics /// /// When calling `product()` and a primitive integer type is being returned, @@ -3721,7 +3732,7 @@ pub trait Iterator { } } - /// Determines if the elements of this [`Iterator`] are unequal to those of + /// Determines if the elements of this [`Iterator`] are not equal to those of /// another. /// /// # Examples diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index af02848233d..c8f60defff7 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -86,4 +86,5 @@ pub unsafe trait InPlaceIterable: Iterator {} /// for details. Consumers are free to rely on the invariants in unsafe code. #[unstable(feature = "trusted_step", issue = "85731")] #[rustc_specialization_trait] -pub unsafe trait TrustedStep: Step {} +#[const_trait] +pub unsafe trait TrustedStep: ~const Step {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24bad799fc8..a6b9acb576e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -95,7 +95,7 @@ #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] -#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))] +#![warn(multiple_supertrait_upcastable)] // // Library features: #![feature(const_align_offset)] @@ -123,9 +123,11 @@ #![feature(const_index_range_slice_index)] #![feature(const_inherent_unchecked_arith)] #![feature(const_int_unchecked_arith)] +#![feature(const_intoiterator_identity)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] #![feature(const_ipv6)] +#![feature(const_iter)] #![feature(const_likely)] #![feature(const_maybe_uninit_uninit_array)] #![feature(const_maybe_uninit_as_mut_ptr)] @@ -207,6 +209,7 @@ #![feature(derive_const)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] +#![feature(generic_arg_infer)] #![feature(rustdoc_internals)] #![feature(exhaustive_patterns)] #![feature(doc_cfg_hide)] @@ -241,7 +244,7 @@ #![feature(unsized_fn_params)] #![feature(asm_const)] #![feature(const_transmute_copy)] -#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))] +#![feature(multiple_supertrait_upcastable)] // // Target features: #![feature(arm_target_feature)] @@ -254,7 +257,6 @@ #![feature(sse4a_target_feature)] #![feature(tbm_target_feature)] #![feature(wasm_target_feature)] -#![cfg_attr(bootstrap, feature(cmpxchg16b_target_feature))] // allow using `core::` in intra-doc links #[allow(unused_extern_crates)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3b026bc0e0f..529f62f4d6c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -340,9 +340,9 @@ pub macro debug_assert_matches($($arg:tt)*) { #[stable(feature = "matches_macro", since = "1.42.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")] macro_rules! matches { - ($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { + ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => { match $expression { - $( $pattern )|+ $( if $guard )? => true, + $pattern $(if $guard)? => true, _ => false } }; diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 427146941ad..9a0fd1f5f51 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -97,7 +97,7 @@ unsafe impl<T: Sync + ?Sized> Send for &T {} #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] #[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_coinductive)] +#[rustc_coinductive] pub trait Sized { // Empty. } @@ -877,8 +877,7 @@ pub trait Tuple {} /// All types that have the same size and alignment as a `usize` or /// `*const ()` automatically implement this trait. #[unstable(feature = "pointer_like_trait", issue = "none")] -#[cfg_attr(bootstrap, lang = "pointer_sized")] -#[cfg_attr(not(bootstrap), lang = "pointer_like")] +#[lang = "pointer_like"] #[rustc_on_unimplemented( message = "`{Self}` needs to have the same alignment and size as a pointer", label = "`{Self}` needs to be a pointer-like type" diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index 0d25ab1d5e1..2d48e271580 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -121,7 +121,7 @@ impl SocketAddr { /// ``` #[stable(feature = "ip_addr", since = "1.7.0")] #[must_use] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn new(ip: IpAddr, port: u16) -> SocketAddr { match ip { IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), @@ -141,7 +141,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "ip_addr", since = "1.7.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn ip(&self) -> IpAddr { match *self { SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), @@ -182,7 +182,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn port(&self) -> u16 { match *self { SocketAddr::V4(ref a) => a.port(), @@ -226,7 +226,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "sockaddr_checker", since = "1.16.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn is_ipv4(&self) -> bool { matches!(*self, SocketAddr::V4(_)) } @@ -248,7 +248,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "sockaddr_checker", since = "1.16.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn is_ipv6(&self) -> bool { matches!(*self, SocketAddr::V6(_)) } @@ -268,7 +268,7 @@ impl SocketAddrV4 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { SocketAddrV4 { ip, port } } @@ -285,7 +285,7 @@ impl SocketAddrV4 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn ip(&self) -> &Ipv4Addr { &self.ip } @@ -318,7 +318,7 @@ impl SocketAddrV4 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn port(&self) -> u16 { self.port } @@ -359,7 +359,7 @@ impl SocketAddrV6 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { SocketAddrV6 { ip, port, flowinfo, scope_id } } @@ -376,7 +376,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn ip(&self) -> &Ipv6Addr { &self.ip } @@ -409,7 +409,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn port(&self) -> u16 { self.port } @@ -452,7 +452,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn flowinfo(&self) -> u32 { self.flowinfo } @@ -492,7 +492,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn scope_id(&self) -> u32 { self.scope_id } diff --git a/library/core/src/num/dec2flt/common.rs b/library/core/src/num/dec2flt/common.rs index 17957d7e770..3e8d75df378 100644 --- a/library/core/src/num/dec2flt/common.rs +++ b/library/core/src/num/dec2flt/common.rs @@ -192,6 +192,7 @@ pub struct BiasedFp { } impl BiasedFp { + #[inline] pub const fn zero_pow2(e: i32) -> Self { Self { f: 0, e } } diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs index 5921c5ed472..1c9d68999d6 100644 --- a/library/core/src/num/dec2flt/float.rs +++ b/library/core/src/num/dec2flt/float.rs @@ -118,11 +118,13 @@ impl RawFloat for f32 { const SMALLEST_POWER_OF_TEN: i32 = -65; const LARGEST_POWER_OF_TEN: i32 = 38; + #[inline] fn from_u64(v: u64) -> Self { debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); v as _ } + #[inline] fn from_u64_bits(v: u64) -> Self { f32::from_bits((v & 0xFFFFFFFF) as u32) } @@ -169,11 +171,13 @@ impl RawFloat for f64 { const SMALLEST_POWER_OF_TEN: i32 = -342; const LARGEST_POWER_OF_TEN: i32 = 308; + #[inline] fn from_u64(v: u64) -> Self { debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); v as _ } + #[inline] fn from_u64_bits(v: u64) -> Self { f64::from_bits(v) } diff --git a/library/core/src/num/dec2flt/lemire.rs b/library/core/src/num/dec2flt/lemire.rs index 9f7594460a1..3bc052df7a6 100644 --- a/library/core/src/num/dec2flt/lemire.rs +++ b/library/core/src/num/dec2flt/lemire.rs @@ -118,10 +118,12 @@ pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp { /// This uses a pre-computed integer approximation for /// log2(10), where 217706 / 2^16 is accurate for the /// entire range of non-finite decimal exponents. +#[inline] fn power(q: i32) -> i32 { (q.wrapping_mul(152_170 + 65536) >> 16) + 63 } +#[inline] fn full_multiplication(a: u64, b: u64) -> (u64, u64) { let r = (a as u128) * (b as u128); (r as u64, (r >> 64) as u64) diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index f8d493e8b62..58ffb950ad8 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -147,7 +147,13 @@ macro_rules! from_str_float_impl { /// representable floating-point number to the number represented /// by `src` (following the same rules for rounding as for the /// results of primitive operations). - #[inline] + // We add the `#[inline(never)]` attribute, since its content will + // be filled with that of `dec2flt`, which has #[inline(always)]. + // Since `dec2flt` is generic, a normal inline attribute on this function + // with `dec2flt` having no attributes results in heavily repeated + // generation of `dec2flt`, despite the fact only a maximum of 2 + // possible instances can ever exist. Adding #[inline(never)] avoids this. + #[inline(never)] fn from_str(src: &str) -> Result<Self, ParseFloatError> { dec2flt(src) } @@ -202,12 +208,14 @@ impl fmt::Display for ParseFloatError { } } +#[inline] pub(super) fn pfe_empty() -> ParseFloatError { ParseFloatError { kind: FloatErrorKind::Empty } } // Used in unit tests, keep public. // This is much better than making FloatErrorKind and ParseFloatError::kind public. +#[inline] pub fn pfe_invalid() -> ParseFloatError { ParseFloatError { kind: FloatErrorKind::Invalid } } @@ -220,6 +228,7 @@ fn biased_fp_to_float<T: RawFloat>(x: BiasedFp) -> T { } /// Converts a decimal string into a floating point number. +#[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above pub fn dec2flt<F: RawFloat>(s: &str) -> Result<F, ParseFloatError> { let mut s = s.as_bytes(); let c = if let Some(&c) = s.first() { diff --git a/library/core/src/num/dec2flt/number.rs b/library/core/src/num/dec2flt/number.rs index 405f7e7b613..8589e2bbd4f 100644 --- a/library/core/src/num/dec2flt/number.rs +++ b/library/core/src/num/dec2flt/number.rs @@ -33,6 +33,7 @@ pub struct Number { impl Number { /// Detect if the float can be accurately reconstructed from native floats. + #[inline] fn is_fast_path<F: RawFloat>(&self) -> bool { F::MIN_EXPONENT_FAST_PATH <= self.exponent && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 86aa1e4fd20..c254803fbf6 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -392,14 +392,7 @@ impl<T> NeverShortCircuit<T> { pub fn wrap_mut_2<A, B>( mut f: impl ~const FnMut(A, B) -> T, ) -> impl ~const FnMut(A, B) -> Self { - cfg_if! { - if #[cfg(bootstrap)] { - #[allow(unused_parens)] - (const move |a, b| NeverShortCircuit(f(a, b))) - } else { - const move |a, b| NeverShortCircuit(f(a, b)) - } - } + const move |a, b| NeverShortCircuit(f(a, b)) } } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0f2475a8bde..cba597e66aa 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -559,6 +559,7 @@ use crate::{ /// The `Option` type. See [the module level documentation](self) for more. #[derive(Copy, PartialOrd, Eq, Ord, Debug, Hash)] #[rustc_diagnostic_item = "Option"] +#[cfg_attr(not(bootstrap), lang = "Option")] #[stable(feature = "rust1", since = "1.0.0")] pub enum Option<T> { /// No value. @@ -735,48 +736,6 @@ impl<T> Option<T> { } } - /// This is a guess at how many bytes into the option the payload can be found. - /// - /// For niche-optimized types it's correct because it's pigeon-holed to only - /// one possible place. For other types, it's usually correct today, but - /// tweaks to the layout algorithm (particularly expansions of - /// `-Z randomize-layout`) might make it incorrect at any point. - /// - /// It's guaranteed to be a multiple of alignment (so will always give a - /// correctly-aligned location) and to be within the allocated object, so - /// is valid to use with `offset` and to use for a zero-sized read. - /// - /// FIXME: This is a horrible hack, but allows a nice optimization. It should - /// be replaced with `offset_of!` once that works on enum variants. - const SOME_BYTE_OFFSET_GUESS: isize = { - let some_uninit = Some(mem::MaybeUninit::<T>::uninit()); - let payload_ref = some_uninit.as_ref().unwrap(); - // SAFETY: `as_ref` gives an address inside the existing `Option`, - // so both pointers are derived from the same thing and the result - // cannot overflow an `isize`. - let offset = unsafe { <*const _>::byte_offset_from(payload_ref, &some_uninit) }; - - // The offset is into the object, so it's guaranteed to be non-negative. - assert!(offset >= 0); - - // The payload and the overall option are aligned, - // so the offset will be a multiple of the alignment too. - assert!((offset as usize) % mem::align_of::<T>() == 0); - - let max_offset = mem::size_of::<Self>() - mem::size_of::<T>(); - if offset as usize <= max_offset { - // There's enough space after this offset for a `T` to exist without - // overflowing the bounds of the object, so let's try it. - offset - } else { - // The offset guess is definitely wrong, so use the address - // of the original option since we have it already. - // This also correctly handles the case of layout-optimized enums - // where `max_offset == 0` and thus this is the only possibility. - 0 - } - }; - /// Returns a slice of the contained value, if any. If this is `None`, an /// empty slice is returned. This can be useful to have a single type of /// iterator over an `Option` or slice. @@ -809,28 +768,29 @@ impl<T> Option<T> { #[must_use] #[unstable(feature = "option_as_slice", issue = "108545")] pub fn as_slice(&self) -> &[T] { - let payload_ptr: *const T = - // The goal here is that both arms here are calculating exactly - // the same pointer, and thus it'll be folded away when the guessed - // offset is correct, but if the guess is wrong for some reason - // it'll at least still be sound, just no longer optimal. - if let Some(payload) = self { - payload - } else { - let self_ptr: *const Self = self; - // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is - // such that this will be in-bounds of the object. - unsafe { self_ptr.byte_offset(Self::SOME_BYTE_OFFSET_GUESS).cast() } - }; - let len = usize::from(self.is_some()); + #[cfg(bootstrap)] + match self { + Some(value) => slice::from_ref(value), + None => &[], + } + #[cfg(not(bootstrap))] // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to // `slice::from_ref`, and thus is safe. // When the `Option` is `None`, the length used is 0, so to be safe it // just needs to be aligned, which it is because `&self` is aligned and // the offset used is a multiple of alignment. - unsafe { slice::from_raw_parts(payload_ptr, len) } + // + // In the new version, the intrinsic always returns a pointer to an + // in-bounds and correctly aligned position for a `T` (even if in the + // `None` case it's just padding). + unsafe { + slice::from_raw_parts( + crate::intrinsics::option_payload_ptr(crate::ptr::from_ref(self)), + usize::from(self.is_some()), + ) + } } /// Returns a mutable slice of the contained value, if any. If this is @@ -875,28 +835,32 @@ impl<T> Option<T> { #[must_use] #[unstable(feature = "option_as_slice", issue = "108545")] pub fn as_mut_slice(&mut self) -> &mut [T] { - let payload_ptr: *mut T = - // The goal here is that both arms here are calculating exactly - // the same pointer, and thus it'll be folded away when the guessed - // offset is correct, but if the guess is wrong for some reason - // it'll at least still be sound, just no longer optimal. - if let Some(payload) = self { - payload - } else { - let self_ptr: *mut Self = self; - // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is - // such that this will be in-bounds of the object. - unsafe { self_ptr.byte_offset(Self::SOME_BYTE_OFFSET_GUESS).cast() } - }; - let len = usize::from(self.is_some()); + #[cfg(bootstrap)] + match self { + Some(value) => slice::from_mut(value), + None => &mut [], + } + #[cfg(not(bootstrap))] // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to // `slice::from_mut`, and thus is safe. // When the `Option` is `None`, the length used is 0, so to be safe it // just needs to be aligned, which it is because `&self` is aligned and // the offset used is a multiple of alignment. - unsafe { slice::from_raw_parts_mut(payload_ptr, len) } + // + // In the new version, the intrinsic creates a `*const T` from a + // mutable reference so it is safe to cast back to a mutable pointer + // here. As with `as_slice`, the intrinsic always returns a pointer to + // an in-bounds and correctly aligned position for a `T` (even if in + // the `None` case it's just padding). + unsafe { + slice::from_raw_parts_mut( + crate::intrinsics::option_payload_ptr(crate::ptr::from_mut(self).cast_const()) + .cast_mut(), + usize::from(self.is_some()), + ) + } } ///////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 805a1e51ae9..35da9151b6f 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -29,6 +29,9 @@ use crate::fmt; use crate::panic::{Location, PanicInfo}; +#[cfg(feature = "panic_immediate_abort")] +const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C panic=abort"); + // First we define the two main entry points that all panics go through. // In the end both are just convenience wrappers around `panic_impl`. @@ -111,7 +114,7 @@ pub const fn panic(expr: &'static str) -> ! { // truncation and padding (even though none is used here). Using // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. - panic_fmt(fmt::Arguments::new_v1(&[expr], &[])); + panic_fmt(fmt::Arguments::new_const(&[expr])); } /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize. @@ -120,7 +123,7 @@ pub const fn panic(expr: &'static str) -> ! { #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] pub fn panic_nounwind(expr: &'static str) -> ! { - panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[])); + panic_nounwind_fmt(fmt::Arguments::new_const(&[expr])); } #[inline] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index febe57dc90b..c4b89a63019 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1003,22 +1003,25 @@ impl<P, U> CoerceUnsized<Pin<U>> for Pin<P> where P: CoerceUnsized<U> {} #[stable(feature = "pin", since = "1.33.0")] impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {} -/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning[^1] a `value: T` _locally_[^2]. +/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning a `value: T` locally. /// -/// Unlike [`Box::pin`], this does not involve a heap allocation. +/// Unlike [`Box::pin`], this does not create a new heap allocation. As explained +/// below, the element might still end up on the heap however. /// -/// [^1]: If the (type `T` of the) given value does not implement [`Unpin`], then this -/// effectively pins the `value` in memory, where it will be unable to be moved. -/// Otherwise, <code>[Pin]<[&mut] T></code> behaves like <code>[&mut] T</code>, and operations such -/// as [`mem::replace()`][crate::mem::replace] will allow extracting that value, and therefore, -/// moving it. -/// See [the `Unpin` section of the `pin` module][self#unpin] for more info. +/// The local pinning performed by this macro is usually dubbed "stack"-pinning. +/// Outside of `async` contexts locals do indeed get stored on the stack. In +/// `async` functions or blocks however, any locals crossing an `.await` point +/// are part of the state captured by the `Future`, and will use the storage of +/// those. That storage can either be on the heap or on the stack. Therefore, +/// local pinning is a more accurate term. /// -/// [^2]: This is usually dubbed "stack"-pinning. And whilst local values are almost always located -/// in the stack (_e.g._, when within the body of a non-`async` function), the truth is that inside -/// the body of an `async fn` or block —more generally, the body of a generator— any locals crossing -/// an `.await` point —a `yield` point— end up being part of the state captured by the `Future` —by -/// the `Generator`—, and thus will be stored wherever that one is. +/// If the type of the given value does not implement [`Unpin`], then this macro +/// pins the value in memory in a way that prevents moves. On the other hand, +/// if the type does implement [`Unpin`], <code>[Pin]<[&mut] T></code> behaves +/// like <code>[&mut] T</code>, and operations such as +/// [`mem::replace()`][crate::mem::replace] or [`mem::take()`](crate::mem::take) +/// will allow moves of the value. +/// See [the `Unpin` section of the `pin` module][self#unpin] for details. /// /// ## Examples /// @@ -1158,9 +1161,9 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {} /// /// If you really need to return a pinned value, consider using [`Box::pin`] instead. /// -/// On the other hand, pinning to the stack[<sup>2</sup>](#fn2) using [`pin!`] is likely to be -/// cheaper than pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not -/// even needing an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`] +/// On the other hand, local pinning using [`pin!`] is likely to be cheaper than +/// pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not +/// requiring an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`] /// constructor. /// /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 6f78811a186..e12a3e378a6 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1110,7 +1110,7 @@ impl<T: Copy> Copy for (T,) { /// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected /// behavior: -/// - It is unequal to any float, including itself! This is the reason `f32` +/// - It is not equal to any float, including itself! This is the reason `f32` /// doesn't implement the `Eq` trait. /// - It is also neither smaller nor greater than any float, making it /// impossible to sort by the default comparison operation, which is the diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index c4317799bcc..88b84bd1352 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -132,9 +132,7 @@ iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, { Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>, { - self.as_slice().windows(2).all(|w| { - compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false) - }) + self.as_slice().is_sorted_by(|a, b| compare(&a, &b)) } }} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d319b2bc37f..57b6e0ce4bb 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3822,7 +3822,7 @@ impl<T> [T] { where F: FnMut(&'a T, &'a T) -> Option<Ordering>, { - self.iter().is_sorted_by(|a, b| compare(*a, *b)) + self.array_windows().all(|[a, b]| compare(a, b).map_or(false, Ordering::is_le)) } /// Checks if the elements of this slice are sorted using the given key extraction function. diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 95c682f42d0..772c3605562 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -13,7 +13,7 @@ use super::from_utf8_unchecked; use super::pattern::Pattern; use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; use super::validations::{next_code_point, next_code_point_reverse}; -use super::LinesAnyMap; +use super::LinesMap; use super::{BytesIsNotEmpty, UnsafeBytesToStr}; use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode}; use super::{IsAsciiWhitespace, IsNotEmpty, IsWhitespace}; @@ -1104,7 +1104,7 @@ generate_pattern_iterators! { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] #[derive(Clone, Debug)] -pub struct Lines<'a>(pub(super) Map<SplitTerminator<'a, char>, LinesAnyMap>); +pub struct Lines<'a>(pub(super) Map<SplitInclusive<'a, char>, LinesMap>); #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Iterator for Lines<'a> { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index ab2f8520ecb..2b23f64732b 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1011,7 +1011,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn lines(&self) -> Lines<'_> { - Lines(self.split_terminator('\n').map(LinesAnyMap)) + Lines(self.split_inclusive('\n').map(LinesMap)) } /// An iterator over the lines of a string. @@ -2604,10 +2604,10 @@ impl Default for &mut str { impl_fn_for_zst! { /// A nameable, cloneable fn type #[derive(Clone)] - struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str { - let l = line.len(); - if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } - else { line } + struct LinesMap impl<'a> Fn = |line: &'a str| -> &'a str { + let Some(line) = line.strip_suffix('\n') else { return line }; + let Some(line) = line.strip_suffix('\r') else { return line }; + line }; #[derive(Clone)] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 123561873a6..2f6b1c74da0 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1951,8 +1951,7 @@ macro_rules! if_not_8_bit { ($_:ident, $($tt:tt)*) => { $($tt)* }; } -#[cfg_attr(not(bootstrap), cfg(target_has_atomic_load_store))] -#[cfg_attr(bootstrap, cfg(target_has_atomic_load_store = "8"))] +#[cfg(target_has_atomic_load_store)] macro_rules! atomic_int { ($cfg_cas:meta, $cfg_align:meta, @@ -3125,8 +3124,7 @@ atomic_int_ptr_sized! { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] fn strongest_failure_ordering(order: Ordering) -> Ordering { match order { Release => Relaxed, @@ -3168,8 +3166,7 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_swap`. @@ -3186,8 +3183,7 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_add). #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_add`. @@ -3204,8 +3200,7 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_sub). #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_sub`. @@ -3221,8 +3216,7 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange<T: Copy>( dst: *mut T, @@ -3257,8 +3251,7 @@ unsafe fn atomic_compare_exchange<T: Copy>( } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange_weak<T: Copy>( dst: *mut T, @@ -3293,8 +3286,7 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>( } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_and` @@ -3310,8 +3302,7 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_nand` @@ -3327,8 +3318,7 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_or` @@ -3344,8 +3334,7 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_xor` @@ -3362,8 +3351,7 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (signed comparison) #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_max` @@ -3380,8 +3368,7 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (signed comparison) #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_min` @@ -3398,8 +3385,7 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (unsigned comparison) #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umax` @@ -3416,8 +3402,7 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (unsigned comparison) #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umin` diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index bd69ca520c2..b25e9df2868 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -580,14 +580,22 @@ pub mod white_space { #[rustfmt::skip] pub mod conversions { + const INDEX_MASK: u32 = 0x400000; + pub fn to_lower(c: char) -> [char; 3] { if c.is_ascii() { [(c as u8).to_ascii_lowercase() as char, '\0', '\0'] } else { - match bsearch_case_table(c, LOWERCASE_TABLE) { - None => [c, '\0', '\0'], - Some(index) => LOWERCASE_TABLE[index].1, - } + LOWERCASE_TABLE + .binary_search_by(|&(key, _)| key.cmp(&c)) + .map(|i| { + let u = LOWERCASE_TABLE[i].1; + char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { + // SAFETY: Index comes from statically generated table + unsafe { *LOWERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } + }) + }) + .unwrap_or([c, '\0', '\0']) } } @@ -595,1800 +603,781 @@ pub mod conversions { if c.is_ascii() { [(c as u8).to_ascii_uppercase() as char, '\0', '\0'] } else { - match bsearch_case_table(c, UPPERCASE_TABLE) { - None => [c, '\0', '\0'], - Some(index) => UPPERCASE_TABLE[index].1, - } + UPPERCASE_TABLE + .binary_search_by(|&(key, _)| key.cmp(&c)) + .map(|i| { + let u = UPPERCASE_TABLE[i].1; + char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { + // SAFETY: Index comes from statically generated table + unsafe { *UPPERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } + }) + }) + .unwrap_or([c, '\0', '\0']) } } - fn bsearch_case_table(c: char, table: &[(char, [char; 3])]) -> Option<usize> { - table.binary_search_by(|&(key, _)| key.cmp(&c)).ok() - } - static LOWERCASE_TABLE: &[(char, [char; 3])] = &[ - ('A', ['a', '\u{0}', '\u{0}']), ('B', ['b', '\u{0}', '\u{0}']), - ('C', ['c', '\u{0}', '\u{0}']), ('D', ['d', '\u{0}', '\u{0}']), - ('E', ['e', '\u{0}', '\u{0}']), ('F', ['f', '\u{0}', '\u{0}']), - ('G', ['g', '\u{0}', '\u{0}']), ('H', ['h', '\u{0}', '\u{0}']), - ('I', ['i', '\u{0}', '\u{0}']), ('J', ['j', '\u{0}', '\u{0}']), - ('K', ['k', '\u{0}', '\u{0}']), ('L', ['l', '\u{0}', '\u{0}']), - ('M', ['m', '\u{0}', '\u{0}']), ('N', ['n', '\u{0}', '\u{0}']), - ('O', ['o', '\u{0}', '\u{0}']), ('P', ['p', '\u{0}', '\u{0}']), - ('Q', ['q', '\u{0}', '\u{0}']), ('R', ['r', '\u{0}', '\u{0}']), - ('S', ['s', '\u{0}', '\u{0}']), ('T', ['t', '\u{0}', '\u{0}']), - ('U', ['u', '\u{0}', '\u{0}']), ('V', ['v', '\u{0}', '\u{0}']), - ('W', ['w', '\u{0}', '\u{0}']), ('X', ['x', '\u{0}', '\u{0}']), - ('Y', ['y', '\u{0}', '\u{0}']), ('Z', ['z', '\u{0}', '\u{0}']), - ('\u{c0}', ['\u{e0}', '\u{0}', '\u{0}']), ('\u{c1}', ['\u{e1}', '\u{0}', '\u{0}']), - ('\u{c2}', ['\u{e2}', '\u{0}', '\u{0}']), ('\u{c3}', ['\u{e3}', '\u{0}', '\u{0}']), - ('\u{c4}', ['\u{e4}', '\u{0}', '\u{0}']), ('\u{c5}', ['\u{e5}', '\u{0}', '\u{0}']), - ('\u{c6}', ['\u{e6}', '\u{0}', '\u{0}']), ('\u{c7}', ['\u{e7}', '\u{0}', '\u{0}']), - ('\u{c8}', ['\u{e8}', '\u{0}', '\u{0}']), ('\u{c9}', ['\u{e9}', '\u{0}', '\u{0}']), - ('\u{ca}', ['\u{ea}', '\u{0}', '\u{0}']), ('\u{cb}', ['\u{eb}', '\u{0}', '\u{0}']), - ('\u{cc}', ['\u{ec}', '\u{0}', '\u{0}']), ('\u{cd}', ['\u{ed}', '\u{0}', '\u{0}']), - ('\u{ce}', ['\u{ee}', '\u{0}', '\u{0}']), ('\u{cf}', ['\u{ef}', '\u{0}', '\u{0}']), - ('\u{d0}', ['\u{f0}', '\u{0}', '\u{0}']), ('\u{d1}', ['\u{f1}', '\u{0}', '\u{0}']), - ('\u{d2}', ['\u{f2}', '\u{0}', '\u{0}']), ('\u{d3}', ['\u{f3}', '\u{0}', '\u{0}']), - ('\u{d4}', ['\u{f4}', '\u{0}', '\u{0}']), ('\u{d5}', ['\u{f5}', '\u{0}', '\u{0}']), - ('\u{d6}', ['\u{f6}', '\u{0}', '\u{0}']), ('\u{d8}', ['\u{f8}', '\u{0}', '\u{0}']), - ('\u{d9}', ['\u{f9}', '\u{0}', '\u{0}']), ('\u{da}', ['\u{fa}', '\u{0}', '\u{0}']), - ('\u{db}', ['\u{fb}', '\u{0}', '\u{0}']), ('\u{dc}', ['\u{fc}', '\u{0}', '\u{0}']), - ('\u{dd}', ['\u{fd}', '\u{0}', '\u{0}']), ('\u{de}', ['\u{fe}', '\u{0}', '\u{0}']), - ('\u{100}', ['\u{101}', '\u{0}', '\u{0}']), ('\u{102}', ['\u{103}', '\u{0}', '\u{0}']), - ('\u{104}', ['\u{105}', '\u{0}', '\u{0}']), ('\u{106}', ['\u{107}', '\u{0}', '\u{0}']), - ('\u{108}', ['\u{109}', '\u{0}', '\u{0}']), ('\u{10a}', ['\u{10b}', '\u{0}', '\u{0}']), - ('\u{10c}', ['\u{10d}', '\u{0}', '\u{0}']), ('\u{10e}', ['\u{10f}', '\u{0}', '\u{0}']), - ('\u{110}', ['\u{111}', '\u{0}', '\u{0}']), ('\u{112}', ['\u{113}', '\u{0}', '\u{0}']), - ('\u{114}', ['\u{115}', '\u{0}', '\u{0}']), ('\u{116}', ['\u{117}', '\u{0}', '\u{0}']), - ('\u{118}', ['\u{119}', '\u{0}', '\u{0}']), ('\u{11a}', ['\u{11b}', '\u{0}', '\u{0}']), - ('\u{11c}', ['\u{11d}', '\u{0}', '\u{0}']), ('\u{11e}', ['\u{11f}', '\u{0}', '\u{0}']), - ('\u{120}', ['\u{121}', '\u{0}', '\u{0}']), ('\u{122}', ['\u{123}', '\u{0}', '\u{0}']), - ('\u{124}', ['\u{125}', '\u{0}', '\u{0}']), ('\u{126}', ['\u{127}', '\u{0}', '\u{0}']), - ('\u{128}', ['\u{129}', '\u{0}', '\u{0}']), ('\u{12a}', ['\u{12b}', '\u{0}', '\u{0}']), - ('\u{12c}', ['\u{12d}', '\u{0}', '\u{0}']), ('\u{12e}', ['\u{12f}', '\u{0}', '\u{0}']), - ('\u{130}', ['i', '\u{307}', '\u{0}']), ('\u{132}', ['\u{133}', '\u{0}', '\u{0}']), - ('\u{134}', ['\u{135}', '\u{0}', '\u{0}']), ('\u{136}', ['\u{137}', '\u{0}', '\u{0}']), - ('\u{139}', ['\u{13a}', '\u{0}', '\u{0}']), ('\u{13b}', ['\u{13c}', '\u{0}', '\u{0}']), - ('\u{13d}', ['\u{13e}', '\u{0}', '\u{0}']), ('\u{13f}', ['\u{140}', '\u{0}', '\u{0}']), - ('\u{141}', ['\u{142}', '\u{0}', '\u{0}']), ('\u{143}', ['\u{144}', '\u{0}', '\u{0}']), - ('\u{145}', ['\u{146}', '\u{0}', '\u{0}']), ('\u{147}', ['\u{148}', '\u{0}', '\u{0}']), - ('\u{14a}', ['\u{14b}', '\u{0}', '\u{0}']), ('\u{14c}', ['\u{14d}', '\u{0}', '\u{0}']), - ('\u{14e}', ['\u{14f}', '\u{0}', '\u{0}']), ('\u{150}', ['\u{151}', '\u{0}', '\u{0}']), - ('\u{152}', ['\u{153}', '\u{0}', '\u{0}']), ('\u{154}', ['\u{155}', '\u{0}', '\u{0}']), - ('\u{156}', ['\u{157}', '\u{0}', '\u{0}']), ('\u{158}', ['\u{159}', '\u{0}', '\u{0}']), - ('\u{15a}', ['\u{15b}', '\u{0}', '\u{0}']), ('\u{15c}', ['\u{15d}', '\u{0}', '\u{0}']), - ('\u{15e}', ['\u{15f}', '\u{0}', '\u{0}']), ('\u{160}', ['\u{161}', '\u{0}', '\u{0}']), - ('\u{162}', ['\u{163}', '\u{0}', '\u{0}']), ('\u{164}', ['\u{165}', '\u{0}', '\u{0}']), - ('\u{166}', ['\u{167}', '\u{0}', '\u{0}']), ('\u{168}', ['\u{169}', '\u{0}', '\u{0}']), - ('\u{16a}', ['\u{16b}', '\u{0}', '\u{0}']), ('\u{16c}', ['\u{16d}', '\u{0}', '\u{0}']), - ('\u{16e}', ['\u{16f}', '\u{0}', '\u{0}']), ('\u{170}', ['\u{171}', '\u{0}', '\u{0}']), - ('\u{172}', ['\u{173}', '\u{0}', '\u{0}']), ('\u{174}', ['\u{175}', '\u{0}', '\u{0}']), - ('\u{176}', ['\u{177}', '\u{0}', '\u{0}']), ('\u{178}', ['\u{ff}', '\u{0}', '\u{0}']), - ('\u{179}', ['\u{17a}', '\u{0}', '\u{0}']), ('\u{17b}', ['\u{17c}', '\u{0}', '\u{0}']), - ('\u{17d}', ['\u{17e}', '\u{0}', '\u{0}']), ('\u{181}', ['\u{253}', '\u{0}', '\u{0}']), - ('\u{182}', ['\u{183}', '\u{0}', '\u{0}']), ('\u{184}', ['\u{185}', '\u{0}', '\u{0}']), - ('\u{186}', ['\u{254}', '\u{0}', '\u{0}']), ('\u{187}', ['\u{188}', '\u{0}', '\u{0}']), - ('\u{189}', ['\u{256}', '\u{0}', '\u{0}']), ('\u{18a}', ['\u{257}', '\u{0}', '\u{0}']), - ('\u{18b}', ['\u{18c}', '\u{0}', '\u{0}']), ('\u{18e}', ['\u{1dd}', '\u{0}', '\u{0}']), - ('\u{18f}', ['\u{259}', '\u{0}', '\u{0}']), ('\u{190}', ['\u{25b}', '\u{0}', '\u{0}']), - ('\u{191}', ['\u{192}', '\u{0}', '\u{0}']), ('\u{193}', ['\u{260}', '\u{0}', '\u{0}']), - ('\u{194}', ['\u{263}', '\u{0}', '\u{0}']), ('\u{196}', ['\u{269}', '\u{0}', '\u{0}']), - ('\u{197}', ['\u{268}', '\u{0}', '\u{0}']), ('\u{198}', ['\u{199}', '\u{0}', '\u{0}']), - ('\u{19c}', ['\u{26f}', '\u{0}', '\u{0}']), ('\u{19d}', ['\u{272}', '\u{0}', '\u{0}']), - ('\u{19f}', ['\u{275}', '\u{0}', '\u{0}']), ('\u{1a0}', ['\u{1a1}', '\u{0}', '\u{0}']), - ('\u{1a2}', ['\u{1a3}', '\u{0}', '\u{0}']), ('\u{1a4}', ['\u{1a5}', '\u{0}', '\u{0}']), - ('\u{1a6}', ['\u{280}', '\u{0}', '\u{0}']), ('\u{1a7}', ['\u{1a8}', '\u{0}', '\u{0}']), - ('\u{1a9}', ['\u{283}', '\u{0}', '\u{0}']), ('\u{1ac}', ['\u{1ad}', '\u{0}', '\u{0}']), - ('\u{1ae}', ['\u{288}', '\u{0}', '\u{0}']), ('\u{1af}', ['\u{1b0}', '\u{0}', '\u{0}']), - ('\u{1b1}', ['\u{28a}', '\u{0}', '\u{0}']), ('\u{1b2}', ['\u{28b}', '\u{0}', '\u{0}']), - ('\u{1b3}', ['\u{1b4}', '\u{0}', '\u{0}']), ('\u{1b5}', ['\u{1b6}', '\u{0}', '\u{0}']), - ('\u{1b7}', ['\u{292}', '\u{0}', '\u{0}']), ('\u{1b8}', ['\u{1b9}', '\u{0}', '\u{0}']), - ('\u{1bc}', ['\u{1bd}', '\u{0}', '\u{0}']), ('\u{1c4}', ['\u{1c6}', '\u{0}', '\u{0}']), - ('\u{1c5}', ['\u{1c6}', '\u{0}', '\u{0}']), ('\u{1c7}', ['\u{1c9}', '\u{0}', '\u{0}']), - ('\u{1c8}', ['\u{1c9}', '\u{0}', '\u{0}']), ('\u{1ca}', ['\u{1cc}', '\u{0}', '\u{0}']), - ('\u{1cb}', ['\u{1cc}', '\u{0}', '\u{0}']), ('\u{1cd}', ['\u{1ce}', '\u{0}', '\u{0}']), - ('\u{1cf}', ['\u{1d0}', '\u{0}', '\u{0}']), ('\u{1d1}', ['\u{1d2}', '\u{0}', '\u{0}']), - ('\u{1d3}', ['\u{1d4}', '\u{0}', '\u{0}']), ('\u{1d5}', ['\u{1d6}', '\u{0}', '\u{0}']), - ('\u{1d7}', ['\u{1d8}', '\u{0}', '\u{0}']), ('\u{1d9}', ['\u{1da}', '\u{0}', '\u{0}']), - ('\u{1db}', ['\u{1dc}', '\u{0}', '\u{0}']), ('\u{1de}', ['\u{1df}', '\u{0}', '\u{0}']), - ('\u{1e0}', ['\u{1e1}', '\u{0}', '\u{0}']), ('\u{1e2}', ['\u{1e3}', '\u{0}', '\u{0}']), - ('\u{1e4}', ['\u{1e5}', '\u{0}', '\u{0}']), ('\u{1e6}', ['\u{1e7}', '\u{0}', '\u{0}']), - ('\u{1e8}', ['\u{1e9}', '\u{0}', '\u{0}']), ('\u{1ea}', ['\u{1eb}', '\u{0}', '\u{0}']), - ('\u{1ec}', ['\u{1ed}', '\u{0}', '\u{0}']), ('\u{1ee}', ['\u{1ef}', '\u{0}', '\u{0}']), - ('\u{1f1}', ['\u{1f3}', '\u{0}', '\u{0}']), ('\u{1f2}', ['\u{1f3}', '\u{0}', '\u{0}']), - ('\u{1f4}', ['\u{1f5}', '\u{0}', '\u{0}']), ('\u{1f6}', ['\u{195}', '\u{0}', '\u{0}']), - ('\u{1f7}', ['\u{1bf}', '\u{0}', '\u{0}']), ('\u{1f8}', ['\u{1f9}', '\u{0}', '\u{0}']), - ('\u{1fa}', ['\u{1fb}', '\u{0}', '\u{0}']), ('\u{1fc}', ['\u{1fd}', '\u{0}', '\u{0}']), - ('\u{1fe}', ['\u{1ff}', '\u{0}', '\u{0}']), ('\u{200}', ['\u{201}', '\u{0}', '\u{0}']), - ('\u{202}', ['\u{203}', '\u{0}', '\u{0}']), ('\u{204}', ['\u{205}', '\u{0}', '\u{0}']), - ('\u{206}', ['\u{207}', '\u{0}', '\u{0}']), ('\u{208}', ['\u{209}', '\u{0}', '\u{0}']), - ('\u{20a}', ['\u{20b}', '\u{0}', '\u{0}']), ('\u{20c}', ['\u{20d}', '\u{0}', '\u{0}']), - ('\u{20e}', ['\u{20f}', '\u{0}', '\u{0}']), ('\u{210}', ['\u{211}', '\u{0}', '\u{0}']), - ('\u{212}', ['\u{213}', '\u{0}', '\u{0}']), ('\u{214}', ['\u{215}', '\u{0}', '\u{0}']), - ('\u{216}', ['\u{217}', '\u{0}', '\u{0}']), ('\u{218}', ['\u{219}', '\u{0}', '\u{0}']), - ('\u{21a}', ['\u{21b}', '\u{0}', '\u{0}']), ('\u{21c}', ['\u{21d}', '\u{0}', '\u{0}']), - ('\u{21e}', ['\u{21f}', '\u{0}', '\u{0}']), ('\u{220}', ['\u{19e}', '\u{0}', '\u{0}']), - ('\u{222}', ['\u{223}', '\u{0}', '\u{0}']), ('\u{224}', ['\u{225}', '\u{0}', '\u{0}']), - ('\u{226}', ['\u{227}', '\u{0}', '\u{0}']), ('\u{228}', ['\u{229}', '\u{0}', '\u{0}']), - ('\u{22a}', ['\u{22b}', '\u{0}', '\u{0}']), ('\u{22c}', ['\u{22d}', '\u{0}', '\u{0}']), - ('\u{22e}', ['\u{22f}', '\u{0}', '\u{0}']), ('\u{230}', ['\u{231}', '\u{0}', '\u{0}']), - ('\u{232}', ['\u{233}', '\u{0}', '\u{0}']), ('\u{23a}', ['\u{2c65}', '\u{0}', '\u{0}']), - ('\u{23b}', ['\u{23c}', '\u{0}', '\u{0}']), ('\u{23d}', ['\u{19a}', '\u{0}', '\u{0}']), - ('\u{23e}', ['\u{2c66}', '\u{0}', '\u{0}']), ('\u{241}', ['\u{242}', '\u{0}', '\u{0}']), - ('\u{243}', ['\u{180}', '\u{0}', '\u{0}']), ('\u{244}', ['\u{289}', '\u{0}', '\u{0}']), - ('\u{245}', ['\u{28c}', '\u{0}', '\u{0}']), ('\u{246}', ['\u{247}', '\u{0}', '\u{0}']), - ('\u{248}', ['\u{249}', '\u{0}', '\u{0}']), ('\u{24a}', ['\u{24b}', '\u{0}', '\u{0}']), - ('\u{24c}', ['\u{24d}', '\u{0}', '\u{0}']), ('\u{24e}', ['\u{24f}', '\u{0}', '\u{0}']), - ('\u{370}', ['\u{371}', '\u{0}', '\u{0}']), ('\u{372}', ['\u{373}', '\u{0}', '\u{0}']), - ('\u{376}', ['\u{377}', '\u{0}', '\u{0}']), ('\u{37f}', ['\u{3f3}', '\u{0}', '\u{0}']), - ('\u{386}', ['\u{3ac}', '\u{0}', '\u{0}']), ('\u{388}', ['\u{3ad}', '\u{0}', '\u{0}']), - ('\u{389}', ['\u{3ae}', '\u{0}', '\u{0}']), ('\u{38a}', ['\u{3af}', '\u{0}', '\u{0}']), - ('\u{38c}', ['\u{3cc}', '\u{0}', '\u{0}']), ('\u{38e}', ['\u{3cd}', '\u{0}', '\u{0}']), - ('\u{38f}', ['\u{3ce}', '\u{0}', '\u{0}']), ('\u{391}', ['\u{3b1}', '\u{0}', '\u{0}']), - ('\u{392}', ['\u{3b2}', '\u{0}', '\u{0}']), ('\u{393}', ['\u{3b3}', '\u{0}', '\u{0}']), - ('\u{394}', ['\u{3b4}', '\u{0}', '\u{0}']), ('\u{395}', ['\u{3b5}', '\u{0}', '\u{0}']), - ('\u{396}', ['\u{3b6}', '\u{0}', '\u{0}']), ('\u{397}', ['\u{3b7}', '\u{0}', '\u{0}']), - ('\u{398}', ['\u{3b8}', '\u{0}', '\u{0}']), ('\u{399}', ['\u{3b9}', '\u{0}', '\u{0}']), - ('\u{39a}', ['\u{3ba}', '\u{0}', '\u{0}']), ('\u{39b}', ['\u{3bb}', '\u{0}', '\u{0}']), - ('\u{39c}', ['\u{3bc}', '\u{0}', '\u{0}']), ('\u{39d}', ['\u{3bd}', '\u{0}', '\u{0}']), - ('\u{39e}', ['\u{3be}', '\u{0}', '\u{0}']), ('\u{39f}', ['\u{3bf}', '\u{0}', '\u{0}']), - ('\u{3a0}', ['\u{3c0}', '\u{0}', '\u{0}']), ('\u{3a1}', ['\u{3c1}', '\u{0}', '\u{0}']), - ('\u{3a3}', ['\u{3c3}', '\u{0}', '\u{0}']), ('\u{3a4}', ['\u{3c4}', '\u{0}', '\u{0}']), - ('\u{3a5}', ['\u{3c5}', '\u{0}', '\u{0}']), ('\u{3a6}', ['\u{3c6}', '\u{0}', '\u{0}']), - ('\u{3a7}', ['\u{3c7}', '\u{0}', '\u{0}']), ('\u{3a8}', ['\u{3c8}', '\u{0}', '\u{0}']), - ('\u{3a9}', ['\u{3c9}', '\u{0}', '\u{0}']), ('\u{3aa}', ['\u{3ca}', '\u{0}', '\u{0}']), - ('\u{3ab}', ['\u{3cb}', '\u{0}', '\u{0}']), ('\u{3cf}', ['\u{3d7}', '\u{0}', '\u{0}']), - ('\u{3d8}', ['\u{3d9}', '\u{0}', '\u{0}']), ('\u{3da}', ['\u{3db}', '\u{0}', '\u{0}']), - ('\u{3dc}', ['\u{3dd}', '\u{0}', '\u{0}']), ('\u{3de}', ['\u{3df}', '\u{0}', '\u{0}']), - ('\u{3e0}', ['\u{3e1}', '\u{0}', '\u{0}']), ('\u{3e2}', ['\u{3e3}', '\u{0}', '\u{0}']), - ('\u{3e4}', ['\u{3e5}', '\u{0}', '\u{0}']), ('\u{3e6}', ['\u{3e7}', '\u{0}', '\u{0}']), - ('\u{3e8}', ['\u{3e9}', '\u{0}', '\u{0}']), ('\u{3ea}', ['\u{3eb}', '\u{0}', '\u{0}']), - ('\u{3ec}', ['\u{3ed}', '\u{0}', '\u{0}']), ('\u{3ee}', ['\u{3ef}', '\u{0}', '\u{0}']), - ('\u{3f4}', ['\u{3b8}', '\u{0}', '\u{0}']), ('\u{3f7}', ['\u{3f8}', '\u{0}', '\u{0}']), - ('\u{3f9}', ['\u{3f2}', '\u{0}', '\u{0}']), ('\u{3fa}', ['\u{3fb}', '\u{0}', '\u{0}']), - ('\u{3fd}', ['\u{37b}', '\u{0}', '\u{0}']), ('\u{3fe}', ['\u{37c}', '\u{0}', '\u{0}']), - ('\u{3ff}', ['\u{37d}', '\u{0}', '\u{0}']), ('\u{400}', ['\u{450}', '\u{0}', '\u{0}']), - ('\u{401}', ['\u{451}', '\u{0}', '\u{0}']), ('\u{402}', ['\u{452}', '\u{0}', '\u{0}']), - ('\u{403}', ['\u{453}', '\u{0}', '\u{0}']), ('\u{404}', ['\u{454}', '\u{0}', '\u{0}']), - ('\u{405}', ['\u{455}', '\u{0}', '\u{0}']), ('\u{406}', ['\u{456}', '\u{0}', '\u{0}']), - ('\u{407}', ['\u{457}', '\u{0}', '\u{0}']), ('\u{408}', ['\u{458}', '\u{0}', '\u{0}']), - ('\u{409}', ['\u{459}', '\u{0}', '\u{0}']), ('\u{40a}', ['\u{45a}', '\u{0}', '\u{0}']), - ('\u{40b}', ['\u{45b}', '\u{0}', '\u{0}']), ('\u{40c}', ['\u{45c}', '\u{0}', '\u{0}']), - ('\u{40d}', ['\u{45d}', '\u{0}', '\u{0}']), ('\u{40e}', ['\u{45e}', '\u{0}', '\u{0}']), - ('\u{40f}', ['\u{45f}', '\u{0}', '\u{0}']), ('\u{410}', ['\u{430}', '\u{0}', '\u{0}']), - ('\u{411}', ['\u{431}', '\u{0}', '\u{0}']), ('\u{412}', ['\u{432}', '\u{0}', '\u{0}']), - ('\u{413}', ['\u{433}', '\u{0}', '\u{0}']), ('\u{414}', ['\u{434}', '\u{0}', '\u{0}']), - ('\u{415}', ['\u{435}', '\u{0}', '\u{0}']), ('\u{416}', ['\u{436}', '\u{0}', '\u{0}']), - ('\u{417}', ['\u{437}', '\u{0}', '\u{0}']), ('\u{418}', ['\u{438}', '\u{0}', '\u{0}']), - ('\u{419}', ['\u{439}', '\u{0}', '\u{0}']), ('\u{41a}', ['\u{43a}', '\u{0}', '\u{0}']), - ('\u{41b}', ['\u{43b}', '\u{0}', '\u{0}']), ('\u{41c}', ['\u{43c}', '\u{0}', '\u{0}']), - ('\u{41d}', ['\u{43d}', '\u{0}', '\u{0}']), ('\u{41e}', ['\u{43e}', '\u{0}', '\u{0}']), - ('\u{41f}', ['\u{43f}', '\u{0}', '\u{0}']), ('\u{420}', ['\u{440}', '\u{0}', '\u{0}']), - ('\u{421}', ['\u{441}', '\u{0}', '\u{0}']), ('\u{422}', ['\u{442}', '\u{0}', '\u{0}']), - ('\u{423}', ['\u{443}', '\u{0}', '\u{0}']), ('\u{424}', ['\u{444}', '\u{0}', '\u{0}']), - ('\u{425}', ['\u{445}', '\u{0}', '\u{0}']), ('\u{426}', ['\u{446}', '\u{0}', '\u{0}']), - ('\u{427}', ['\u{447}', '\u{0}', '\u{0}']), ('\u{428}', ['\u{448}', '\u{0}', '\u{0}']), - ('\u{429}', ['\u{449}', '\u{0}', '\u{0}']), ('\u{42a}', ['\u{44a}', '\u{0}', '\u{0}']), - ('\u{42b}', ['\u{44b}', '\u{0}', '\u{0}']), ('\u{42c}', ['\u{44c}', '\u{0}', '\u{0}']), - ('\u{42d}', ['\u{44d}', '\u{0}', '\u{0}']), ('\u{42e}', ['\u{44e}', '\u{0}', '\u{0}']), - ('\u{42f}', ['\u{44f}', '\u{0}', '\u{0}']), ('\u{460}', ['\u{461}', '\u{0}', '\u{0}']), - ('\u{462}', ['\u{463}', '\u{0}', '\u{0}']), ('\u{464}', ['\u{465}', '\u{0}', '\u{0}']), - ('\u{466}', ['\u{467}', '\u{0}', '\u{0}']), ('\u{468}', ['\u{469}', '\u{0}', '\u{0}']), - ('\u{46a}', ['\u{46b}', '\u{0}', '\u{0}']), ('\u{46c}', ['\u{46d}', '\u{0}', '\u{0}']), - ('\u{46e}', ['\u{46f}', '\u{0}', '\u{0}']), ('\u{470}', ['\u{471}', '\u{0}', '\u{0}']), - ('\u{472}', ['\u{473}', '\u{0}', '\u{0}']), ('\u{474}', ['\u{475}', '\u{0}', '\u{0}']), - ('\u{476}', ['\u{477}', '\u{0}', '\u{0}']), ('\u{478}', ['\u{479}', '\u{0}', '\u{0}']), - ('\u{47a}', ['\u{47b}', '\u{0}', '\u{0}']), ('\u{47c}', ['\u{47d}', '\u{0}', '\u{0}']), - ('\u{47e}', ['\u{47f}', '\u{0}', '\u{0}']), ('\u{480}', ['\u{481}', '\u{0}', '\u{0}']), - ('\u{48a}', ['\u{48b}', '\u{0}', '\u{0}']), ('\u{48c}', ['\u{48d}', '\u{0}', '\u{0}']), - ('\u{48e}', ['\u{48f}', '\u{0}', '\u{0}']), ('\u{490}', ['\u{491}', '\u{0}', '\u{0}']), - ('\u{492}', ['\u{493}', '\u{0}', '\u{0}']), ('\u{494}', ['\u{495}', '\u{0}', '\u{0}']), - ('\u{496}', ['\u{497}', '\u{0}', '\u{0}']), ('\u{498}', ['\u{499}', '\u{0}', '\u{0}']), - ('\u{49a}', ['\u{49b}', '\u{0}', '\u{0}']), ('\u{49c}', ['\u{49d}', '\u{0}', '\u{0}']), - ('\u{49e}', ['\u{49f}', '\u{0}', '\u{0}']), ('\u{4a0}', ['\u{4a1}', '\u{0}', '\u{0}']), - ('\u{4a2}', ['\u{4a3}', '\u{0}', '\u{0}']), ('\u{4a4}', ['\u{4a5}', '\u{0}', '\u{0}']), - ('\u{4a6}', ['\u{4a7}', '\u{0}', '\u{0}']), ('\u{4a8}', ['\u{4a9}', '\u{0}', '\u{0}']), - ('\u{4aa}', ['\u{4ab}', '\u{0}', '\u{0}']), ('\u{4ac}', ['\u{4ad}', '\u{0}', '\u{0}']), - ('\u{4ae}', ['\u{4af}', '\u{0}', '\u{0}']), ('\u{4b0}', ['\u{4b1}', '\u{0}', '\u{0}']), - ('\u{4b2}', ['\u{4b3}', '\u{0}', '\u{0}']), ('\u{4b4}', ['\u{4b5}', '\u{0}', '\u{0}']), - ('\u{4b6}', ['\u{4b7}', '\u{0}', '\u{0}']), ('\u{4b8}', ['\u{4b9}', '\u{0}', '\u{0}']), - ('\u{4ba}', ['\u{4bb}', '\u{0}', '\u{0}']), ('\u{4bc}', ['\u{4bd}', '\u{0}', '\u{0}']), - ('\u{4be}', ['\u{4bf}', '\u{0}', '\u{0}']), ('\u{4c0}', ['\u{4cf}', '\u{0}', '\u{0}']), - ('\u{4c1}', ['\u{4c2}', '\u{0}', '\u{0}']), ('\u{4c3}', ['\u{4c4}', '\u{0}', '\u{0}']), - ('\u{4c5}', ['\u{4c6}', '\u{0}', '\u{0}']), ('\u{4c7}', ['\u{4c8}', '\u{0}', '\u{0}']), - ('\u{4c9}', ['\u{4ca}', '\u{0}', '\u{0}']), ('\u{4cb}', ['\u{4cc}', '\u{0}', '\u{0}']), - ('\u{4cd}', ['\u{4ce}', '\u{0}', '\u{0}']), ('\u{4d0}', ['\u{4d1}', '\u{0}', '\u{0}']), - ('\u{4d2}', ['\u{4d3}', '\u{0}', '\u{0}']), ('\u{4d4}', ['\u{4d5}', '\u{0}', '\u{0}']), - ('\u{4d6}', ['\u{4d7}', '\u{0}', '\u{0}']), ('\u{4d8}', ['\u{4d9}', '\u{0}', '\u{0}']), - ('\u{4da}', ['\u{4db}', '\u{0}', '\u{0}']), ('\u{4dc}', ['\u{4dd}', '\u{0}', '\u{0}']), - ('\u{4de}', ['\u{4df}', '\u{0}', '\u{0}']), ('\u{4e0}', ['\u{4e1}', '\u{0}', '\u{0}']), - ('\u{4e2}', ['\u{4e3}', '\u{0}', '\u{0}']), ('\u{4e4}', ['\u{4e5}', '\u{0}', '\u{0}']), - ('\u{4e6}', ['\u{4e7}', '\u{0}', '\u{0}']), ('\u{4e8}', ['\u{4e9}', '\u{0}', '\u{0}']), - ('\u{4ea}', ['\u{4eb}', '\u{0}', '\u{0}']), ('\u{4ec}', ['\u{4ed}', '\u{0}', '\u{0}']), - ('\u{4ee}', ['\u{4ef}', '\u{0}', '\u{0}']), ('\u{4f0}', ['\u{4f1}', '\u{0}', '\u{0}']), - ('\u{4f2}', ['\u{4f3}', '\u{0}', '\u{0}']), ('\u{4f4}', ['\u{4f5}', '\u{0}', '\u{0}']), - ('\u{4f6}', ['\u{4f7}', '\u{0}', '\u{0}']), ('\u{4f8}', ['\u{4f9}', '\u{0}', '\u{0}']), - ('\u{4fa}', ['\u{4fb}', '\u{0}', '\u{0}']), ('\u{4fc}', ['\u{4fd}', '\u{0}', '\u{0}']), - ('\u{4fe}', ['\u{4ff}', '\u{0}', '\u{0}']), ('\u{500}', ['\u{501}', '\u{0}', '\u{0}']), - ('\u{502}', ['\u{503}', '\u{0}', '\u{0}']), ('\u{504}', ['\u{505}', '\u{0}', '\u{0}']), - ('\u{506}', ['\u{507}', '\u{0}', '\u{0}']), ('\u{508}', ['\u{509}', '\u{0}', '\u{0}']), - ('\u{50a}', ['\u{50b}', '\u{0}', '\u{0}']), ('\u{50c}', ['\u{50d}', '\u{0}', '\u{0}']), - ('\u{50e}', ['\u{50f}', '\u{0}', '\u{0}']), ('\u{510}', ['\u{511}', '\u{0}', '\u{0}']), - ('\u{512}', ['\u{513}', '\u{0}', '\u{0}']), ('\u{514}', ['\u{515}', '\u{0}', '\u{0}']), - ('\u{516}', ['\u{517}', '\u{0}', '\u{0}']), ('\u{518}', ['\u{519}', '\u{0}', '\u{0}']), - ('\u{51a}', ['\u{51b}', '\u{0}', '\u{0}']), ('\u{51c}', ['\u{51d}', '\u{0}', '\u{0}']), - ('\u{51e}', ['\u{51f}', '\u{0}', '\u{0}']), ('\u{520}', ['\u{521}', '\u{0}', '\u{0}']), - ('\u{522}', ['\u{523}', '\u{0}', '\u{0}']), ('\u{524}', ['\u{525}', '\u{0}', '\u{0}']), - ('\u{526}', ['\u{527}', '\u{0}', '\u{0}']), ('\u{528}', ['\u{529}', '\u{0}', '\u{0}']), - ('\u{52a}', ['\u{52b}', '\u{0}', '\u{0}']), ('\u{52c}', ['\u{52d}', '\u{0}', '\u{0}']), - ('\u{52e}', ['\u{52f}', '\u{0}', '\u{0}']), ('\u{531}', ['\u{561}', '\u{0}', '\u{0}']), - ('\u{532}', ['\u{562}', '\u{0}', '\u{0}']), ('\u{533}', ['\u{563}', '\u{0}', '\u{0}']), - ('\u{534}', ['\u{564}', '\u{0}', '\u{0}']), ('\u{535}', ['\u{565}', '\u{0}', '\u{0}']), - ('\u{536}', ['\u{566}', '\u{0}', '\u{0}']), ('\u{537}', ['\u{567}', '\u{0}', '\u{0}']), - ('\u{538}', ['\u{568}', '\u{0}', '\u{0}']), ('\u{539}', ['\u{569}', '\u{0}', '\u{0}']), - ('\u{53a}', ['\u{56a}', '\u{0}', '\u{0}']), ('\u{53b}', ['\u{56b}', '\u{0}', '\u{0}']), - ('\u{53c}', ['\u{56c}', '\u{0}', '\u{0}']), ('\u{53d}', ['\u{56d}', '\u{0}', '\u{0}']), - ('\u{53e}', ['\u{56e}', '\u{0}', '\u{0}']), ('\u{53f}', ['\u{56f}', '\u{0}', '\u{0}']), - ('\u{540}', ['\u{570}', '\u{0}', '\u{0}']), ('\u{541}', ['\u{571}', '\u{0}', '\u{0}']), - ('\u{542}', ['\u{572}', '\u{0}', '\u{0}']), ('\u{543}', ['\u{573}', '\u{0}', '\u{0}']), - ('\u{544}', ['\u{574}', '\u{0}', '\u{0}']), ('\u{545}', ['\u{575}', '\u{0}', '\u{0}']), - ('\u{546}', ['\u{576}', '\u{0}', '\u{0}']), ('\u{547}', ['\u{577}', '\u{0}', '\u{0}']), - ('\u{548}', ['\u{578}', '\u{0}', '\u{0}']), ('\u{549}', ['\u{579}', '\u{0}', '\u{0}']), - ('\u{54a}', ['\u{57a}', '\u{0}', '\u{0}']), ('\u{54b}', ['\u{57b}', '\u{0}', '\u{0}']), - ('\u{54c}', ['\u{57c}', '\u{0}', '\u{0}']), ('\u{54d}', ['\u{57d}', '\u{0}', '\u{0}']), - ('\u{54e}', ['\u{57e}', '\u{0}', '\u{0}']), ('\u{54f}', ['\u{57f}', '\u{0}', '\u{0}']), - ('\u{550}', ['\u{580}', '\u{0}', '\u{0}']), ('\u{551}', ['\u{581}', '\u{0}', '\u{0}']), - ('\u{552}', ['\u{582}', '\u{0}', '\u{0}']), ('\u{553}', ['\u{583}', '\u{0}', '\u{0}']), - ('\u{554}', ['\u{584}', '\u{0}', '\u{0}']), ('\u{555}', ['\u{585}', '\u{0}', '\u{0}']), - ('\u{556}', ['\u{586}', '\u{0}', '\u{0}']), ('\u{10a0}', ['\u{2d00}', '\u{0}', '\u{0}']), - ('\u{10a1}', ['\u{2d01}', '\u{0}', '\u{0}']), ('\u{10a2}', ['\u{2d02}', '\u{0}', '\u{0}']), - ('\u{10a3}', ['\u{2d03}', '\u{0}', '\u{0}']), ('\u{10a4}', ['\u{2d04}', '\u{0}', '\u{0}']), - ('\u{10a5}', ['\u{2d05}', '\u{0}', '\u{0}']), ('\u{10a6}', ['\u{2d06}', '\u{0}', '\u{0}']), - ('\u{10a7}', ['\u{2d07}', '\u{0}', '\u{0}']), ('\u{10a8}', ['\u{2d08}', '\u{0}', '\u{0}']), - ('\u{10a9}', ['\u{2d09}', '\u{0}', '\u{0}']), ('\u{10aa}', ['\u{2d0a}', '\u{0}', '\u{0}']), - ('\u{10ab}', ['\u{2d0b}', '\u{0}', '\u{0}']), ('\u{10ac}', ['\u{2d0c}', '\u{0}', '\u{0}']), - ('\u{10ad}', ['\u{2d0d}', '\u{0}', '\u{0}']), ('\u{10ae}', ['\u{2d0e}', '\u{0}', '\u{0}']), - ('\u{10af}', ['\u{2d0f}', '\u{0}', '\u{0}']), ('\u{10b0}', ['\u{2d10}', '\u{0}', '\u{0}']), - ('\u{10b1}', ['\u{2d11}', '\u{0}', '\u{0}']), ('\u{10b2}', ['\u{2d12}', '\u{0}', '\u{0}']), - ('\u{10b3}', ['\u{2d13}', '\u{0}', '\u{0}']), ('\u{10b4}', ['\u{2d14}', '\u{0}', '\u{0}']), - ('\u{10b5}', ['\u{2d15}', '\u{0}', '\u{0}']), ('\u{10b6}', ['\u{2d16}', '\u{0}', '\u{0}']), - ('\u{10b7}', ['\u{2d17}', '\u{0}', '\u{0}']), ('\u{10b8}', ['\u{2d18}', '\u{0}', '\u{0}']), - ('\u{10b9}', ['\u{2d19}', '\u{0}', '\u{0}']), ('\u{10ba}', ['\u{2d1a}', '\u{0}', '\u{0}']), - ('\u{10bb}', ['\u{2d1b}', '\u{0}', '\u{0}']), ('\u{10bc}', ['\u{2d1c}', '\u{0}', '\u{0}']), - ('\u{10bd}', ['\u{2d1d}', '\u{0}', '\u{0}']), ('\u{10be}', ['\u{2d1e}', '\u{0}', '\u{0}']), - ('\u{10bf}', ['\u{2d1f}', '\u{0}', '\u{0}']), ('\u{10c0}', ['\u{2d20}', '\u{0}', '\u{0}']), - ('\u{10c1}', ['\u{2d21}', '\u{0}', '\u{0}']), ('\u{10c2}', ['\u{2d22}', '\u{0}', '\u{0}']), - ('\u{10c3}', ['\u{2d23}', '\u{0}', '\u{0}']), ('\u{10c4}', ['\u{2d24}', '\u{0}', '\u{0}']), - ('\u{10c5}', ['\u{2d25}', '\u{0}', '\u{0}']), ('\u{10c7}', ['\u{2d27}', '\u{0}', '\u{0}']), - ('\u{10cd}', ['\u{2d2d}', '\u{0}', '\u{0}']), ('\u{13a0}', ['\u{ab70}', '\u{0}', '\u{0}']), - ('\u{13a1}', ['\u{ab71}', '\u{0}', '\u{0}']), ('\u{13a2}', ['\u{ab72}', '\u{0}', '\u{0}']), - ('\u{13a3}', ['\u{ab73}', '\u{0}', '\u{0}']), ('\u{13a4}', ['\u{ab74}', '\u{0}', '\u{0}']), - ('\u{13a5}', ['\u{ab75}', '\u{0}', '\u{0}']), ('\u{13a6}', ['\u{ab76}', '\u{0}', '\u{0}']), - ('\u{13a7}', ['\u{ab77}', '\u{0}', '\u{0}']), ('\u{13a8}', ['\u{ab78}', '\u{0}', '\u{0}']), - ('\u{13a9}', ['\u{ab79}', '\u{0}', '\u{0}']), ('\u{13aa}', ['\u{ab7a}', '\u{0}', '\u{0}']), - ('\u{13ab}', ['\u{ab7b}', '\u{0}', '\u{0}']), ('\u{13ac}', ['\u{ab7c}', '\u{0}', '\u{0}']), - ('\u{13ad}', ['\u{ab7d}', '\u{0}', '\u{0}']), ('\u{13ae}', ['\u{ab7e}', '\u{0}', '\u{0}']), - ('\u{13af}', ['\u{ab7f}', '\u{0}', '\u{0}']), ('\u{13b0}', ['\u{ab80}', '\u{0}', '\u{0}']), - ('\u{13b1}', ['\u{ab81}', '\u{0}', '\u{0}']), ('\u{13b2}', ['\u{ab82}', '\u{0}', '\u{0}']), - ('\u{13b3}', ['\u{ab83}', '\u{0}', '\u{0}']), ('\u{13b4}', ['\u{ab84}', '\u{0}', '\u{0}']), - ('\u{13b5}', ['\u{ab85}', '\u{0}', '\u{0}']), ('\u{13b6}', ['\u{ab86}', '\u{0}', '\u{0}']), - ('\u{13b7}', ['\u{ab87}', '\u{0}', '\u{0}']), ('\u{13b8}', ['\u{ab88}', '\u{0}', '\u{0}']), - ('\u{13b9}', ['\u{ab89}', '\u{0}', '\u{0}']), ('\u{13ba}', ['\u{ab8a}', '\u{0}', '\u{0}']), - ('\u{13bb}', ['\u{ab8b}', '\u{0}', '\u{0}']), ('\u{13bc}', ['\u{ab8c}', '\u{0}', '\u{0}']), - ('\u{13bd}', ['\u{ab8d}', '\u{0}', '\u{0}']), ('\u{13be}', ['\u{ab8e}', '\u{0}', '\u{0}']), - ('\u{13bf}', ['\u{ab8f}', '\u{0}', '\u{0}']), ('\u{13c0}', ['\u{ab90}', '\u{0}', '\u{0}']), - ('\u{13c1}', ['\u{ab91}', '\u{0}', '\u{0}']), ('\u{13c2}', ['\u{ab92}', '\u{0}', '\u{0}']), - ('\u{13c3}', ['\u{ab93}', '\u{0}', '\u{0}']), ('\u{13c4}', ['\u{ab94}', '\u{0}', '\u{0}']), - ('\u{13c5}', ['\u{ab95}', '\u{0}', '\u{0}']), ('\u{13c6}', ['\u{ab96}', '\u{0}', '\u{0}']), - ('\u{13c7}', ['\u{ab97}', '\u{0}', '\u{0}']), ('\u{13c8}', ['\u{ab98}', '\u{0}', '\u{0}']), - ('\u{13c9}', ['\u{ab99}', '\u{0}', '\u{0}']), ('\u{13ca}', ['\u{ab9a}', '\u{0}', '\u{0}']), - ('\u{13cb}', ['\u{ab9b}', '\u{0}', '\u{0}']), ('\u{13cc}', ['\u{ab9c}', '\u{0}', '\u{0}']), - ('\u{13cd}', ['\u{ab9d}', '\u{0}', '\u{0}']), ('\u{13ce}', ['\u{ab9e}', '\u{0}', '\u{0}']), - ('\u{13cf}', ['\u{ab9f}', '\u{0}', '\u{0}']), ('\u{13d0}', ['\u{aba0}', '\u{0}', '\u{0}']), - ('\u{13d1}', ['\u{aba1}', '\u{0}', '\u{0}']), ('\u{13d2}', ['\u{aba2}', '\u{0}', '\u{0}']), - ('\u{13d3}', ['\u{aba3}', '\u{0}', '\u{0}']), ('\u{13d4}', ['\u{aba4}', '\u{0}', '\u{0}']), - ('\u{13d5}', ['\u{aba5}', '\u{0}', '\u{0}']), ('\u{13d6}', ['\u{aba6}', '\u{0}', '\u{0}']), - ('\u{13d7}', ['\u{aba7}', '\u{0}', '\u{0}']), ('\u{13d8}', ['\u{aba8}', '\u{0}', '\u{0}']), - ('\u{13d9}', ['\u{aba9}', '\u{0}', '\u{0}']), ('\u{13da}', ['\u{abaa}', '\u{0}', '\u{0}']), - ('\u{13db}', ['\u{abab}', '\u{0}', '\u{0}']), ('\u{13dc}', ['\u{abac}', '\u{0}', '\u{0}']), - ('\u{13dd}', ['\u{abad}', '\u{0}', '\u{0}']), ('\u{13de}', ['\u{abae}', '\u{0}', '\u{0}']), - ('\u{13df}', ['\u{abaf}', '\u{0}', '\u{0}']), ('\u{13e0}', ['\u{abb0}', '\u{0}', '\u{0}']), - ('\u{13e1}', ['\u{abb1}', '\u{0}', '\u{0}']), ('\u{13e2}', ['\u{abb2}', '\u{0}', '\u{0}']), - ('\u{13e3}', ['\u{abb3}', '\u{0}', '\u{0}']), ('\u{13e4}', ['\u{abb4}', '\u{0}', '\u{0}']), - ('\u{13e5}', ['\u{abb5}', '\u{0}', '\u{0}']), ('\u{13e6}', ['\u{abb6}', '\u{0}', '\u{0}']), - ('\u{13e7}', ['\u{abb7}', '\u{0}', '\u{0}']), ('\u{13e8}', ['\u{abb8}', '\u{0}', '\u{0}']), - ('\u{13e9}', ['\u{abb9}', '\u{0}', '\u{0}']), ('\u{13ea}', ['\u{abba}', '\u{0}', '\u{0}']), - ('\u{13eb}', ['\u{abbb}', '\u{0}', '\u{0}']), ('\u{13ec}', ['\u{abbc}', '\u{0}', '\u{0}']), - ('\u{13ed}', ['\u{abbd}', '\u{0}', '\u{0}']), ('\u{13ee}', ['\u{abbe}', '\u{0}', '\u{0}']), - ('\u{13ef}', ['\u{abbf}', '\u{0}', '\u{0}']), ('\u{13f0}', ['\u{13f8}', '\u{0}', '\u{0}']), - ('\u{13f1}', ['\u{13f9}', '\u{0}', '\u{0}']), ('\u{13f2}', ['\u{13fa}', '\u{0}', '\u{0}']), - ('\u{13f3}', ['\u{13fb}', '\u{0}', '\u{0}']), ('\u{13f4}', ['\u{13fc}', '\u{0}', '\u{0}']), - ('\u{13f5}', ['\u{13fd}', '\u{0}', '\u{0}']), ('\u{1c90}', ['\u{10d0}', '\u{0}', '\u{0}']), - ('\u{1c91}', ['\u{10d1}', '\u{0}', '\u{0}']), ('\u{1c92}', ['\u{10d2}', '\u{0}', '\u{0}']), - ('\u{1c93}', ['\u{10d3}', '\u{0}', '\u{0}']), ('\u{1c94}', ['\u{10d4}', '\u{0}', '\u{0}']), - ('\u{1c95}', ['\u{10d5}', '\u{0}', '\u{0}']), ('\u{1c96}', ['\u{10d6}', '\u{0}', '\u{0}']), - ('\u{1c97}', ['\u{10d7}', '\u{0}', '\u{0}']), ('\u{1c98}', ['\u{10d8}', '\u{0}', '\u{0}']), - ('\u{1c99}', ['\u{10d9}', '\u{0}', '\u{0}']), ('\u{1c9a}', ['\u{10da}', '\u{0}', '\u{0}']), - ('\u{1c9b}', ['\u{10db}', '\u{0}', '\u{0}']), ('\u{1c9c}', ['\u{10dc}', '\u{0}', '\u{0}']), - ('\u{1c9d}', ['\u{10dd}', '\u{0}', '\u{0}']), ('\u{1c9e}', ['\u{10de}', '\u{0}', '\u{0}']), - ('\u{1c9f}', ['\u{10df}', '\u{0}', '\u{0}']), ('\u{1ca0}', ['\u{10e0}', '\u{0}', '\u{0}']), - ('\u{1ca1}', ['\u{10e1}', '\u{0}', '\u{0}']), ('\u{1ca2}', ['\u{10e2}', '\u{0}', '\u{0}']), - ('\u{1ca3}', ['\u{10e3}', '\u{0}', '\u{0}']), ('\u{1ca4}', ['\u{10e4}', '\u{0}', '\u{0}']), - ('\u{1ca5}', ['\u{10e5}', '\u{0}', '\u{0}']), ('\u{1ca6}', ['\u{10e6}', '\u{0}', '\u{0}']), - ('\u{1ca7}', ['\u{10e7}', '\u{0}', '\u{0}']), ('\u{1ca8}', ['\u{10e8}', '\u{0}', '\u{0}']), - ('\u{1ca9}', ['\u{10e9}', '\u{0}', '\u{0}']), ('\u{1caa}', ['\u{10ea}', '\u{0}', '\u{0}']), - ('\u{1cab}', ['\u{10eb}', '\u{0}', '\u{0}']), ('\u{1cac}', ['\u{10ec}', '\u{0}', '\u{0}']), - ('\u{1cad}', ['\u{10ed}', '\u{0}', '\u{0}']), ('\u{1cae}', ['\u{10ee}', '\u{0}', '\u{0}']), - ('\u{1caf}', ['\u{10ef}', '\u{0}', '\u{0}']), ('\u{1cb0}', ['\u{10f0}', '\u{0}', '\u{0}']), - ('\u{1cb1}', ['\u{10f1}', '\u{0}', '\u{0}']), ('\u{1cb2}', ['\u{10f2}', '\u{0}', '\u{0}']), - ('\u{1cb3}', ['\u{10f3}', '\u{0}', '\u{0}']), ('\u{1cb4}', ['\u{10f4}', '\u{0}', '\u{0}']), - ('\u{1cb5}', ['\u{10f5}', '\u{0}', '\u{0}']), ('\u{1cb6}', ['\u{10f6}', '\u{0}', '\u{0}']), - ('\u{1cb7}', ['\u{10f7}', '\u{0}', '\u{0}']), ('\u{1cb8}', ['\u{10f8}', '\u{0}', '\u{0}']), - ('\u{1cb9}', ['\u{10f9}', '\u{0}', '\u{0}']), ('\u{1cba}', ['\u{10fa}', '\u{0}', '\u{0}']), - ('\u{1cbd}', ['\u{10fd}', '\u{0}', '\u{0}']), ('\u{1cbe}', ['\u{10fe}', '\u{0}', '\u{0}']), - ('\u{1cbf}', ['\u{10ff}', '\u{0}', '\u{0}']), ('\u{1e00}', ['\u{1e01}', '\u{0}', '\u{0}']), - ('\u{1e02}', ['\u{1e03}', '\u{0}', '\u{0}']), ('\u{1e04}', ['\u{1e05}', '\u{0}', '\u{0}']), - ('\u{1e06}', ['\u{1e07}', '\u{0}', '\u{0}']), ('\u{1e08}', ['\u{1e09}', '\u{0}', '\u{0}']), - ('\u{1e0a}', ['\u{1e0b}', '\u{0}', '\u{0}']), ('\u{1e0c}', ['\u{1e0d}', '\u{0}', '\u{0}']), - ('\u{1e0e}', ['\u{1e0f}', '\u{0}', '\u{0}']), ('\u{1e10}', ['\u{1e11}', '\u{0}', '\u{0}']), - ('\u{1e12}', ['\u{1e13}', '\u{0}', '\u{0}']), ('\u{1e14}', ['\u{1e15}', '\u{0}', '\u{0}']), - ('\u{1e16}', ['\u{1e17}', '\u{0}', '\u{0}']), ('\u{1e18}', ['\u{1e19}', '\u{0}', '\u{0}']), - ('\u{1e1a}', ['\u{1e1b}', '\u{0}', '\u{0}']), ('\u{1e1c}', ['\u{1e1d}', '\u{0}', '\u{0}']), - ('\u{1e1e}', ['\u{1e1f}', '\u{0}', '\u{0}']), ('\u{1e20}', ['\u{1e21}', '\u{0}', '\u{0}']), - ('\u{1e22}', ['\u{1e23}', '\u{0}', '\u{0}']), ('\u{1e24}', ['\u{1e25}', '\u{0}', '\u{0}']), - ('\u{1e26}', ['\u{1e27}', '\u{0}', '\u{0}']), ('\u{1e28}', ['\u{1e29}', '\u{0}', '\u{0}']), - ('\u{1e2a}', ['\u{1e2b}', '\u{0}', '\u{0}']), ('\u{1e2c}', ['\u{1e2d}', '\u{0}', '\u{0}']), - ('\u{1e2e}', ['\u{1e2f}', '\u{0}', '\u{0}']), ('\u{1e30}', ['\u{1e31}', '\u{0}', '\u{0}']), - ('\u{1e32}', ['\u{1e33}', '\u{0}', '\u{0}']), ('\u{1e34}', ['\u{1e35}', '\u{0}', '\u{0}']), - ('\u{1e36}', ['\u{1e37}', '\u{0}', '\u{0}']), ('\u{1e38}', ['\u{1e39}', '\u{0}', '\u{0}']), - ('\u{1e3a}', ['\u{1e3b}', '\u{0}', '\u{0}']), ('\u{1e3c}', ['\u{1e3d}', '\u{0}', '\u{0}']), - ('\u{1e3e}', ['\u{1e3f}', '\u{0}', '\u{0}']), ('\u{1e40}', ['\u{1e41}', '\u{0}', '\u{0}']), - ('\u{1e42}', ['\u{1e43}', '\u{0}', '\u{0}']), ('\u{1e44}', ['\u{1e45}', '\u{0}', '\u{0}']), - ('\u{1e46}', ['\u{1e47}', '\u{0}', '\u{0}']), ('\u{1e48}', ['\u{1e49}', '\u{0}', '\u{0}']), - ('\u{1e4a}', ['\u{1e4b}', '\u{0}', '\u{0}']), ('\u{1e4c}', ['\u{1e4d}', '\u{0}', '\u{0}']), - ('\u{1e4e}', ['\u{1e4f}', '\u{0}', '\u{0}']), ('\u{1e50}', ['\u{1e51}', '\u{0}', '\u{0}']), - ('\u{1e52}', ['\u{1e53}', '\u{0}', '\u{0}']), ('\u{1e54}', ['\u{1e55}', '\u{0}', '\u{0}']), - ('\u{1e56}', ['\u{1e57}', '\u{0}', '\u{0}']), ('\u{1e58}', ['\u{1e59}', '\u{0}', '\u{0}']), - ('\u{1e5a}', ['\u{1e5b}', '\u{0}', '\u{0}']), ('\u{1e5c}', ['\u{1e5d}', '\u{0}', '\u{0}']), - ('\u{1e5e}', ['\u{1e5f}', '\u{0}', '\u{0}']), ('\u{1e60}', ['\u{1e61}', '\u{0}', '\u{0}']), - ('\u{1e62}', ['\u{1e63}', '\u{0}', '\u{0}']), ('\u{1e64}', ['\u{1e65}', '\u{0}', '\u{0}']), - ('\u{1e66}', ['\u{1e67}', '\u{0}', '\u{0}']), ('\u{1e68}', ['\u{1e69}', '\u{0}', '\u{0}']), - ('\u{1e6a}', ['\u{1e6b}', '\u{0}', '\u{0}']), ('\u{1e6c}', ['\u{1e6d}', '\u{0}', '\u{0}']), - ('\u{1e6e}', ['\u{1e6f}', '\u{0}', '\u{0}']), ('\u{1e70}', ['\u{1e71}', '\u{0}', '\u{0}']), - ('\u{1e72}', ['\u{1e73}', '\u{0}', '\u{0}']), ('\u{1e74}', ['\u{1e75}', '\u{0}', '\u{0}']), - ('\u{1e76}', ['\u{1e77}', '\u{0}', '\u{0}']), ('\u{1e78}', ['\u{1e79}', '\u{0}', '\u{0}']), - ('\u{1e7a}', ['\u{1e7b}', '\u{0}', '\u{0}']), ('\u{1e7c}', ['\u{1e7d}', '\u{0}', '\u{0}']), - ('\u{1e7e}', ['\u{1e7f}', '\u{0}', '\u{0}']), ('\u{1e80}', ['\u{1e81}', '\u{0}', '\u{0}']), - ('\u{1e82}', ['\u{1e83}', '\u{0}', '\u{0}']), ('\u{1e84}', ['\u{1e85}', '\u{0}', '\u{0}']), - ('\u{1e86}', ['\u{1e87}', '\u{0}', '\u{0}']), ('\u{1e88}', ['\u{1e89}', '\u{0}', '\u{0}']), - ('\u{1e8a}', ['\u{1e8b}', '\u{0}', '\u{0}']), ('\u{1e8c}', ['\u{1e8d}', '\u{0}', '\u{0}']), - ('\u{1e8e}', ['\u{1e8f}', '\u{0}', '\u{0}']), ('\u{1e90}', ['\u{1e91}', '\u{0}', '\u{0}']), - ('\u{1e92}', ['\u{1e93}', '\u{0}', '\u{0}']), ('\u{1e94}', ['\u{1e95}', '\u{0}', '\u{0}']), - ('\u{1e9e}', ['\u{df}', '\u{0}', '\u{0}']), ('\u{1ea0}', ['\u{1ea1}', '\u{0}', '\u{0}']), - ('\u{1ea2}', ['\u{1ea3}', '\u{0}', '\u{0}']), ('\u{1ea4}', ['\u{1ea5}', '\u{0}', '\u{0}']), - ('\u{1ea6}', ['\u{1ea7}', '\u{0}', '\u{0}']), ('\u{1ea8}', ['\u{1ea9}', '\u{0}', '\u{0}']), - ('\u{1eaa}', ['\u{1eab}', '\u{0}', '\u{0}']), ('\u{1eac}', ['\u{1ead}', '\u{0}', '\u{0}']), - ('\u{1eae}', ['\u{1eaf}', '\u{0}', '\u{0}']), ('\u{1eb0}', ['\u{1eb1}', '\u{0}', '\u{0}']), - ('\u{1eb2}', ['\u{1eb3}', '\u{0}', '\u{0}']), ('\u{1eb4}', ['\u{1eb5}', '\u{0}', '\u{0}']), - ('\u{1eb6}', ['\u{1eb7}', '\u{0}', '\u{0}']), ('\u{1eb8}', ['\u{1eb9}', '\u{0}', '\u{0}']), - ('\u{1eba}', ['\u{1ebb}', '\u{0}', '\u{0}']), ('\u{1ebc}', ['\u{1ebd}', '\u{0}', '\u{0}']), - ('\u{1ebe}', ['\u{1ebf}', '\u{0}', '\u{0}']), ('\u{1ec0}', ['\u{1ec1}', '\u{0}', '\u{0}']), - ('\u{1ec2}', ['\u{1ec3}', '\u{0}', '\u{0}']), ('\u{1ec4}', ['\u{1ec5}', '\u{0}', '\u{0}']), - ('\u{1ec6}', ['\u{1ec7}', '\u{0}', '\u{0}']), ('\u{1ec8}', ['\u{1ec9}', '\u{0}', '\u{0}']), - ('\u{1eca}', ['\u{1ecb}', '\u{0}', '\u{0}']), ('\u{1ecc}', ['\u{1ecd}', '\u{0}', '\u{0}']), - ('\u{1ece}', ['\u{1ecf}', '\u{0}', '\u{0}']), ('\u{1ed0}', ['\u{1ed1}', '\u{0}', '\u{0}']), - ('\u{1ed2}', ['\u{1ed3}', '\u{0}', '\u{0}']), ('\u{1ed4}', ['\u{1ed5}', '\u{0}', '\u{0}']), - ('\u{1ed6}', ['\u{1ed7}', '\u{0}', '\u{0}']), ('\u{1ed8}', ['\u{1ed9}', '\u{0}', '\u{0}']), - ('\u{1eda}', ['\u{1edb}', '\u{0}', '\u{0}']), ('\u{1edc}', ['\u{1edd}', '\u{0}', '\u{0}']), - ('\u{1ede}', ['\u{1edf}', '\u{0}', '\u{0}']), ('\u{1ee0}', ['\u{1ee1}', '\u{0}', '\u{0}']), - ('\u{1ee2}', ['\u{1ee3}', '\u{0}', '\u{0}']), ('\u{1ee4}', ['\u{1ee5}', '\u{0}', '\u{0}']), - ('\u{1ee6}', ['\u{1ee7}', '\u{0}', '\u{0}']), ('\u{1ee8}', ['\u{1ee9}', '\u{0}', '\u{0}']), - ('\u{1eea}', ['\u{1eeb}', '\u{0}', '\u{0}']), ('\u{1eec}', ['\u{1eed}', '\u{0}', '\u{0}']), - ('\u{1eee}', ['\u{1eef}', '\u{0}', '\u{0}']), ('\u{1ef0}', ['\u{1ef1}', '\u{0}', '\u{0}']), - ('\u{1ef2}', ['\u{1ef3}', '\u{0}', '\u{0}']), ('\u{1ef4}', ['\u{1ef5}', '\u{0}', '\u{0}']), - ('\u{1ef6}', ['\u{1ef7}', '\u{0}', '\u{0}']), ('\u{1ef8}', ['\u{1ef9}', '\u{0}', '\u{0}']), - ('\u{1efa}', ['\u{1efb}', '\u{0}', '\u{0}']), ('\u{1efc}', ['\u{1efd}', '\u{0}', '\u{0}']), - ('\u{1efe}', ['\u{1eff}', '\u{0}', '\u{0}']), ('\u{1f08}', ['\u{1f00}', '\u{0}', '\u{0}']), - ('\u{1f09}', ['\u{1f01}', '\u{0}', '\u{0}']), ('\u{1f0a}', ['\u{1f02}', '\u{0}', '\u{0}']), - ('\u{1f0b}', ['\u{1f03}', '\u{0}', '\u{0}']), ('\u{1f0c}', ['\u{1f04}', '\u{0}', '\u{0}']), - ('\u{1f0d}', ['\u{1f05}', '\u{0}', '\u{0}']), ('\u{1f0e}', ['\u{1f06}', '\u{0}', '\u{0}']), - ('\u{1f0f}', ['\u{1f07}', '\u{0}', '\u{0}']), ('\u{1f18}', ['\u{1f10}', '\u{0}', '\u{0}']), - ('\u{1f19}', ['\u{1f11}', '\u{0}', '\u{0}']), ('\u{1f1a}', ['\u{1f12}', '\u{0}', '\u{0}']), - ('\u{1f1b}', ['\u{1f13}', '\u{0}', '\u{0}']), ('\u{1f1c}', ['\u{1f14}', '\u{0}', '\u{0}']), - ('\u{1f1d}', ['\u{1f15}', '\u{0}', '\u{0}']), ('\u{1f28}', ['\u{1f20}', '\u{0}', '\u{0}']), - ('\u{1f29}', ['\u{1f21}', '\u{0}', '\u{0}']), ('\u{1f2a}', ['\u{1f22}', '\u{0}', '\u{0}']), - ('\u{1f2b}', ['\u{1f23}', '\u{0}', '\u{0}']), ('\u{1f2c}', ['\u{1f24}', '\u{0}', '\u{0}']), - ('\u{1f2d}', ['\u{1f25}', '\u{0}', '\u{0}']), ('\u{1f2e}', ['\u{1f26}', '\u{0}', '\u{0}']), - ('\u{1f2f}', ['\u{1f27}', '\u{0}', '\u{0}']), ('\u{1f38}', ['\u{1f30}', '\u{0}', '\u{0}']), - ('\u{1f39}', ['\u{1f31}', '\u{0}', '\u{0}']), ('\u{1f3a}', ['\u{1f32}', '\u{0}', '\u{0}']), - ('\u{1f3b}', ['\u{1f33}', '\u{0}', '\u{0}']), ('\u{1f3c}', ['\u{1f34}', '\u{0}', '\u{0}']), - ('\u{1f3d}', ['\u{1f35}', '\u{0}', '\u{0}']), ('\u{1f3e}', ['\u{1f36}', '\u{0}', '\u{0}']), - ('\u{1f3f}', ['\u{1f37}', '\u{0}', '\u{0}']), ('\u{1f48}', ['\u{1f40}', '\u{0}', '\u{0}']), - ('\u{1f49}', ['\u{1f41}', '\u{0}', '\u{0}']), ('\u{1f4a}', ['\u{1f42}', '\u{0}', '\u{0}']), - ('\u{1f4b}', ['\u{1f43}', '\u{0}', '\u{0}']), ('\u{1f4c}', ['\u{1f44}', '\u{0}', '\u{0}']), - ('\u{1f4d}', ['\u{1f45}', '\u{0}', '\u{0}']), ('\u{1f59}', ['\u{1f51}', '\u{0}', '\u{0}']), - ('\u{1f5b}', ['\u{1f53}', '\u{0}', '\u{0}']), ('\u{1f5d}', ['\u{1f55}', '\u{0}', '\u{0}']), - ('\u{1f5f}', ['\u{1f57}', '\u{0}', '\u{0}']), ('\u{1f68}', ['\u{1f60}', '\u{0}', '\u{0}']), - ('\u{1f69}', ['\u{1f61}', '\u{0}', '\u{0}']), ('\u{1f6a}', ['\u{1f62}', '\u{0}', '\u{0}']), - ('\u{1f6b}', ['\u{1f63}', '\u{0}', '\u{0}']), ('\u{1f6c}', ['\u{1f64}', '\u{0}', '\u{0}']), - ('\u{1f6d}', ['\u{1f65}', '\u{0}', '\u{0}']), ('\u{1f6e}', ['\u{1f66}', '\u{0}', '\u{0}']), - ('\u{1f6f}', ['\u{1f67}', '\u{0}', '\u{0}']), ('\u{1f88}', ['\u{1f80}', '\u{0}', '\u{0}']), - ('\u{1f89}', ['\u{1f81}', '\u{0}', '\u{0}']), ('\u{1f8a}', ['\u{1f82}', '\u{0}', '\u{0}']), - ('\u{1f8b}', ['\u{1f83}', '\u{0}', '\u{0}']), ('\u{1f8c}', ['\u{1f84}', '\u{0}', '\u{0}']), - ('\u{1f8d}', ['\u{1f85}', '\u{0}', '\u{0}']), ('\u{1f8e}', ['\u{1f86}', '\u{0}', '\u{0}']), - ('\u{1f8f}', ['\u{1f87}', '\u{0}', '\u{0}']), ('\u{1f98}', ['\u{1f90}', '\u{0}', '\u{0}']), - ('\u{1f99}', ['\u{1f91}', '\u{0}', '\u{0}']), ('\u{1f9a}', ['\u{1f92}', '\u{0}', '\u{0}']), - ('\u{1f9b}', ['\u{1f93}', '\u{0}', '\u{0}']), ('\u{1f9c}', ['\u{1f94}', '\u{0}', '\u{0}']), - ('\u{1f9d}', ['\u{1f95}', '\u{0}', '\u{0}']), ('\u{1f9e}', ['\u{1f96}', '\u{0}', '\u{0}']), - ('\u{1f9f}', ['\u{1f97}', '\u{0}', '\u{0}']), ('\u{1fa8}', ['\u{1fa0}', '\u{0}', '\u{0}']), - ('\u{1fa9}', ['\u{1fa1}', '\u{0}', '\u{0}']), ('\u{1faa}', ['\u{1fa2}', '\u{0}', '\u{0}']), - ('\u{1fab}', ['\u{1fa3}', '\u{0}', '\u{0}']), ('\u{1fac}', ['\u{1fa4}', '\u{0}', '\u{0}']), - ('\u{1fad}', ['\u{1fa5}', '\u{0}', '\u{0}']), ('\u{1fae}', ['\u{1fa6}', '\u{0}', '\u{0}']), - ('\u{1faf}', ['\u{1fa7}', '\u{0}', '\u{0}']), ('\u{1fb8}', ['\u{1fb0}', '\u{0}', '\u{0}']), - ('\u{1fb9}', ['\u{1fb1}', '\u{0}', '\u{0}']), ('\u{1fba}', ['\u{1f70}', '\u{0}', '\u{0}']), - ('\u{1fbb}', ['\u{1f71}', '\u{0}', '\u{0}']), ('\u{1fbc}', ['\u{1fb3}', '\u{0}', '\u{0}']), - ('\u{1fc8}', ['\u{1f72}', '\u{0}', '\u{0}']), ('\u{1fc9}', ['\u{1f73}', '\u{0}', '\u{0}']), - ('\u{1fca}', ['\u{1f74}', '\u{0}', '\u{0}']), ('\u{1fcb}', ['\u{1f75}', '\u{0}', '\u{0}']), - ('\u{1fcc}', ['\u{1fc3}', '\u{0}', '\u{0}']), ('\u{1fd8}', ['\u{1fd0}', '\u{0}', '\u{0}']), - ('\u{1fd9}', ['\u{1fd1}', '\u{0}', '\u{0}']), ('\u{1fda}', ['\u{1f76}', '\u{0}', '\u{0}']), - ('\u{1fdb}', ['\u{1f77}', '\u{0}', '\u{0}']), ('\u{1fe8}', ['\u{1fe0}', '\u{0}', '\u{0}']), - ('\u{1fe9}', ['\u{1fe1}', '\u{0}', '\u{0}']), ('\u{1fea}', ['\u{1f7a}', '\u{0}', '\u{0}']), - ('\u{1feb}', ['\u{1f7b}', '\u{0}', '\u{0}']), ('\u{1fec}', ['\u{1fe5}', '\u{0}', '\u{0}']), - ('\u{1ff8}', ['\u{1f78}', '\u{0}', '\u{0}']), ('\u{1ff9}', ['\u{1f79}', '\u{0}', '\u{0}']), - ('\u{1ffa}', ['\u{1f7c}', '\u{0}', '\u{0}']), ('\u{1ffb}', ['\u{1f7d}', '\u{0}', '\u{0}']), - ('\u{1ffc}', ['\u{1ff3}', '\u{0}', '\u{0}']), ('\u{2126}', ['\u{3c9}', '\u{0}', '\u{0}']), - ('\u{212a}', ['k', '\u{0}', '\u{0}']), ('\u{212b}', ['\u{e5}', '\u{0}', '\u{0}']), - ('\u{2132}', ['\u{214e}', '\u{0}', '\u{0}']), ('\u{2160}', ['\u{2170}', '\u{0}', '\u{0}']), - ('\u{2161}', ['\u{2171}', '\u{0}', '\u{0}']), ('\u{2162}', ['\u{2172}', '\u{0}', '\u{0}']), - ('\u{2163}', ['\u{2173}', '\u{0}', '\u{0}']), ('\u{2164}', ['\u{2174}', '\u{0}', '\u{0}']), - ('\u{2165}', ['\u{2175}', '\u{0}', '\u{0}']), ('\u{2166}', ['\u{2176}', '\u{0}', '\u{0}']), - ('\u{2167}', ['\u{2177}', '\u{0}', '\u{0}']), ('\u{2168}', ['\u{2178}', '\u{0}', '\u{0}']), - ('\u{2169}', ['\u{2179}', '\u{0}', '\u{0}']), ('\u{216a}', ['\u{217a}', '\u{0}', '\u{0}']), - ('\u{216b}', ['\u{217b}', '\u{0}', '\u{0}']), ('\u{216c}', ['\u{217c}', '\u{0}', '\u{0}']), - ('\u{216d}', ['\u{217d}', '\u{0}', '\u{0}']), ('\u{216e}', ['\u{217e}', '\u{0}', '\u{0}']), - ('\u{216f}', ['\u{217f}', '\u{0}', '\u{0}']), ('\u{2183}', ['\u{2184}', '\u{0}', '\u{0}']), - ('\u{24b6}', ['\u{24d0}', '\u{0}', '\u{0}']), ('\u{24b7}', ['\u{24d1}', '\u{0}', '\u{0}']), - ('\u{24b8}', ['\u{24d2}', '\u{0}', '\u{0}']), ('\u{24b9}', ['\u{24d3}', '\u{0}', '\u{0}']), - ('\u{24ba}', ['\u{24d4}', '\u{0}', '\u{0}']), ('\u{24bb}', ['\u{24d5}', '\u{0}', '\u{0}']), - ('\u{24bc}', ['\u{24d6}', '\u{0}', '\u{0}']), ('\u{24bd}', ['\u{24d7}', '\u{0}', '\u{0}']), - ('\u{24be}', ['\u{24d8}', '\u{0}', '\u{0}']), ('\u{24bf}', ['\u{24d9}', '\u{0}', '\u{0}']), - ('\u{24c0}', ['\u{24da}', '\u{0}', '\u{0}']), ('\u{24c1}', ['\u{24db}', '\u{0}', '\u{0}']), - ('\u{24c2}', ['\u{24dc}', '\u{0}', '\u{0}']), ('\u{24c3}', ['\u{24dd}', '\u{0}', '\u{0}']), - ('\u{24c4}', ['\u{24de}', '\u{0}', '\u{0}']), ('\u{24c5}', ['\u{24df}', '\u{0}', '\u{0}']), - ('\u{24c6}', ['\u{24e0}', '\u{0}', '\u{0}']), ('\u{24c7}', ['\u{24e1}', '\u{0}', '\u{0}']), - ('\u{24c8}', ['\u{24e2}', '\u{0}', '\u{0}']), ('\u{24c9}', ['\u{24e3}', '\u{0}', '\u{0}']), - ('\u{24ca}', ['\u{24e4}', '\u{0}', '\u{0}']), ('\u{24cb}', ['\u{24e5}', '\u{0}', '\u{0}']), - ('\u{24cc}', ['\u{24e6}', '\u{0}', '\u{0}']), ('\u{24cd}', ['\u{24e7}', '\u{0}', '\u{0}']), - ('\u{24ce}', ['\u{24e8}', '\u{0}', '\u{0}']), ('\u{24cf}', ['\u{24e9}', '\u{0}', '\u{0}']), - ('\u{2c00}', ['\u{2c30}', '\u{0}', '\u{0}']), ('\u{2c01}', ['\u{2c31}', '\u{0}', '\u{0}']), - ('\u{2c02}', ['\u{2c32}', '\u{0}', '\u{0}']), ('\u{2c03}', ['\u{2c33}', '\u{0}', '\u{0}']), - ('\u{2c04}', ['\u{2c34}', '\u{0}', '\u{0}']), ('\u{2c05}', ['\u{2c35}', '\u{0}', '\u{0}']), - ('\u{2c06}', ['\u{2c36}', '\u{0}', '\u{0}']), ('\u{2c07}', ['\u{2c37}', '\u{0}', '\u{0}']), - ('\u{2c08}', ['\u{2c38}', '\u{0}', '\u{0}']), ('\u{2c09}', ['\u{2c39}', '\u{0}', '\u{0}']), - ('\u{2c0a}', ['\u{2c3a}', '\u{0}', '\u{0}']), ('\u{2c0b}', ['\u{2c3b}', '\u{0}', '\u{0}']), - ('\u{2c0c}', ['\u{2c3c}', '\u{0}', '\u{0}']), ('\u{2c0d}', ['\u{2c3d}', '\u{0}', '\u{0}']), - ('\u{2c0e}', ['\u{2c3e}', '\u{0}', '\u{0}']), ('\u{2c0f}', ['\u{2c3f}', '\u{0}', '\u{0}']), - ('\u{2c10}', ['\u{2c40}', '\u{0}', '\u{0}']), ('\u{2c11}', ['\u{2c41}', '\u{0}', '\u{0}']), - ('\u{2c12}', ['\u{2c42}', '\u{0}', '\u{0}']), ('\u{2c13}', ['\u{2c43}', '\u{0}', '\u{0}']), - ('\u{2c14}', ['\u{2c44}', '\u{0}', '\u{0}']), ('\u{2c15}', ['\u{2c45}', '\u{0}', '\u{0}']), - ('\u{2c16}', ['\u{2c46}', '\u{0}', '\u{0}']), ('\u{2c17}', ['\u{2c47}', '\u{0}', '\u{0}']), - ('\u{2c18}', ['\u{2c48}', '\u{0}', '\u{0}']), ('\u{2c19}', ['\u{2c49}', '\u{0}', '\u{0}']), - ('\u{2c1a}', ['\u{2c4a}', '\u{0}', '\u{0}']), ('\u{2c1b}', ['\u{2c4b}', '\u{0}', '\u{0}']), - ('\u{2c1c}', ['\u{2c4c}', '\u{0}', '\u{0}']), ('\u{2c1d}', ['\u{2c4d}', '\u{0}', '\u{0}']), - ('\u{2c1e}', ['\u{2c4e}', '\u{0}', '\u{0}']), ('\u{2c1f}', ['\u{2c4f}', '\u{0}', '\u{0}']), - ('\u{2c20}', ['\u{2c50}', '\u{0}', '\u{0}']), ('\u{2c21}', ['\u{2c51}', '\u{0}', '\u{0}']), - ('\u{2c22}', ['\u{2c52}', '\u{0}', '\u{0}']), ('\u{2c23}', ['\u{2c53}', '\u{0}', '\u{0}']), - ('\u{2c24}', ['\u{2c54}', '\u{0}', '\u{0}']), ('\u{2c25}', ['\u{2c55}', '\u{0}', '\u{0}']), - ('\u{2c26}', ['\u{2c56}', '\u{0}', '\u{0}']), ('\u{2c27}', ['\u{2c57}', '\u{0}', '\u{0}']), - ('\u{2c28}', ['\u{2c58}', '\u{0}', '\u{0}']), ('\u{2c29}', ['\u{2c59}', '\u{0}', '\u{0}']), - ('\u{2c2a}', ['\u{2c5a}', '\u{0}', '\u{0}']), ('\u{2c2b}', ['\u{2c5b}', '\u{0}', '\u{0}']), - ('\u{2c2c}', ['\u{2c5c}', '\u{0}', '\u{0}']), ('\u{2c2d}', ['\u{2c5d}', '\u{0}', '\u{0}']), - ('\u{2c2e}', ['\u{2c5e}', '\u{0}', '\u{0}']), ('\u{2c2f}', ['\u{2c5f}', '\u{0}', '\u{0}']), - ('\u{2c60}', ['\u{2c61}', '\u{0}', '\u{0}']), ('\u{2c62}', ['\u{26b}', '\u{0}', '\u{0}']), - ('\u{2c63}', ['\u{1d7d}', '\u{0}', '\u{0}']), ('\u{2c64}', ['\u{27d}', '\u{0}', '\u{0}']), - ('\u{2c67}', ['\u{2c68}', '\u{0}', '\u{0}']), ('\u{2c69}', ['\u{2c6a}', '\u{0}', '\u{0}']), - ('\u{2c6b}', ['\u{2c6c}', '\u{0}', '\u{0}']), ('\u{2c6d}', ['\u{251}', '\u{0}', '\u{0}']), - ('\u{2c6e}', ['\u{271}', '\u{0}', '\u{0}']), ('\u{2c6f}', ['\u{250}', '\u{0}', '\u{0}']), - ('\u{2c70}', ['\u{252}', '\u{0}', '\u{0}']), ('\u{2c72}', ['\u{2c73}', '\u{0}', '\u{0}']), - ('\u{2c75}', ['\u{2c76}', '\u{0}', '\u{0}']), ('\u{2c7e}', ['\u{23f}', '\u{0}', '\u{0}']), - ('\u{2c7f}', ['\u{240}', '\u{0}', '\u{0}']), ('\u{2c80}', ['\u{2c81}', '\u{0}', '\u{0}']), - ('\u{2c82}', ['\u{2c83}', '\u{0}', '\u{0}']), ('\u{2c84}', ['\u{2c85}', '\u{0}', '\u{0}']), - ('\u{2c86}', ['\u{2c87}', '\u{0}', '\u{0}']), ('\u{2c88}', ['\u{2c89}', '\u{0}', '\u{0}']), - ('\u{2c8a}', ['\u{2c8b}', '\u{0}', '\u{0}']), ('\u{2c8c}', ['\u{2c8d}', '\u{0}', '\u{0}']), - ('\u{2c8e}', ['\u{2c8f}', '\u{0}', '\u{0}']), ('\u{2c90}', ['\u{2c91}', '\u{0}', '\u{0}']), - ('\u{2c92}', ['\u{2c93}', '\u{0}', '\u{0}']), ('\u{2c94}', ['\u{2c95}', '\u{0}', '\u{0}']), - ('\u{2c96}', ['\u{2c97}', '\u{0}', '\u{0}']), ('\u{2c98}', ['\u{2c99}', '\u{0}', '\u{0}']), - ('\u{2c9a}', ['\u{2c9b}', '\u{0}', '\u{0}']), ('\u{2c9c}', ['\u{2c9d}', '\u{0}', '\u{0}']), - ('\u{2c9e}', ['\u{2c9f}', '\u{0}', '\u{0}']), ('\u{2ca0}', ['\u{2ca1}', '\u{0}', '\u{0}']), - ('\u{2ca2}', ['\u{2ca3}', '\u{0}', '\u{0}']), ('\u{2ca4}', ['\u{2ca5}', '\u{0}', '\u{0}']), - ('\u{2ca6}', ['\u{2ca7}', '\u{0}', '\u{0}']), ('\u{2ca8}', ['\u{2ca9}', '\u{0}', '\u{0}']), - ('\u{2caa}', ['\u{2cab}', '\u{0}', '\u{0}']), ('\u{2cac}', ['\u{2cad}', '\u{0}', '\u{0}']), - ('\u{2cae}', ['\u{2caf}', '\u{0}', '\u{0}']), ('\u{2cb0}', ['\u{2cb1}', '\u{0}', '\u{0}']), - ('\u{2cb2}', ['\u{2cb3}', '\u{0}', '\u{0}']), ('\u{2cb4}', ['\u{2cb5}', '\u{0}', '\u{0}']), - ('\u{2cb6}', ['\u{2cb7}', '\u{0}', '\u{0}']), ('\u{2cb8}', ['\u{2cb9}', '\u{0}', '\u{0}']), - ('\u{2cba}', ['\u{2cbb}', '\u{0}', '\u{0}']), ('\u{2cbc}', ['\u{2cbd}', '\u{0}', '\u{0}']), - ('\u{2cbe}', ['\u{2cbf}', '\u{0}', '\u{0}']), ('\u{2cc0}', ['\u{2cc1}', '\u{0}', '\u{0}']), - ('\u{2cc2}', ['\u{2cc3}', '\u{0}', '\u{0}']), ('\u{2cc4}', ['\u{2cc5}', '\u{0}', '\u{0}']), - ('\u{2cc6}', ['\u{2cc7}', '\u{0}', '\u{0}']), ('\u{2cc8}', ['\u{2cc9}', '\u{0}', '\u{0}']), - ('\u{2cca}', ['\u{2ccb}', '\u{0}', '\u{0}']), ('\u{2ccc}', ['\u{2ccd}', '\u{0}', '\u{0}']), - ('\u{2cce}', ['\u{2ccf}', '\u{0}', '\u{0}']), ('\u{2cd0}', ['\u{2cd1}', '\u{0}', '\u{0}']), - ('\u{2cd2}', ['\u{2cd3}', '\u{0}', '\u{0}']), ('\u{2cd4}', ['\u{2cd5}', '\u{0}', '\u{0}']), - ('\u{2cd6}', ['\u{2cd7}', '\u{0}', '\u{0}']), ('\u{2cd8}', ['\u{2cd9}', '\u{0}', '\u{0}']), - ('\u{2cda}', ['\u{2cdb}', '\u{0}', '\u{0}']), ('\u{2cdc}', ['\u{2cdd}', '\u{0}', '\u{0}']), - ('\u{2cde}', ['\u{2cdf}', '\u{0}', '\u{0}']), ('\u{2ce0}', ['\u{2ce1}', '\u{0}', '\u{0}']), - ('\u{2ce2}', ['\u{2ce3}', '\u{0}', '\u{0}']), ('\u{2ceb}', ['\u{2cec}', '\u{0}', '\u{0}']), - ('\u{2ced}', ['\u{2cee}', '\u{0}', '\u{0}']), ('\u{2cf2}', ['\u{2cf3}', '\u{0}', '\u{0}']), - ('\u{a640}', ['\u{a641}', '\u{0}', '\u{0}']), ('\u{a642}', ['\u{a643}', '\u{0}', '\u{0}']), - ('\u{a644}', ['\u{a645}', '\u{0}', '\u{0}']), ('\u{a646}', ['\u{a647}', '\u{0}', '\u{0}']), - ('\u{a648}', ['\u{a649}', '\u{0}', '\u{0}']), ('\u{a64a}', ['\u{a64b}', '\u{0}', '\u{0}']), - ('\u{a64c}', ['\u{a64d}', '\u{0}', '\u{0}']), ('\u{a64e}', ['\u{a64f}', '\u{0}', '\u{0}']), - ('\u{a650}', ['\u{a651}', '\u{0}', '\u{0}']), ('\u{a652}', ['\u{a653}', '\u{0}', '\u{0}']), - ('\u{a654}', ['\u{a655}', '\u{0}', '\u{0}']), ('\u{a656}', ['\u{a657}', '\u{0}', '\u{0}']), - ('\u{a658}', ['\u{a659}', '\u{0}', '\u{0}']), ('\u{a65a}', ['\u{a65b}', '\u{0}', '\u{0}']), - ('\u{a65c}', ['\u{a65d}', '\u{0}', '\u{0}']), ('\u{a65e}', ['\u{a65f}', '\u{0}', '\u{0}']), - ('\u{a660}', ['\u{a661}', '\u{0}', '\u{0}']), ('\u{a662}', ['\u{a663}', '\u{0}', '\u{0}']), - ('\u{a664}', ['\u{a665}', '\u{0}', '\u{0}']), ('\u{a666}', ['\u{a667}', '\u{0}', '\u{0}']), - ('\u{a668}', ['\u{a669}', '\u{0}', '\u{0}']), ('\u{a66a}', ['\u{a66b}', '\u{0}', '\u{0}']), - ('\u{a66c}', ['\u{a66d}', '\u{0}', '\u{0}']), ('\u{a680}', ['\u{a681}', '\u{0}', '\u{0}']), - ('\u{a682}', ['\u{a683}', '\u{0}', '\u{0}']), ('\u{a684}', ['\u{a685}', '\u{0}', '\u{0}']), - ('\u{a686}', ['\u{a687}', '\u{0}', '\u{0}']), ('\u{a688}', ['\u{a689}', '\u{0}', '\u{0}']), - ('\u{a68a}', ['\u{a68b}', '\u{0}', '\u{0}']), ('\u{a68c}', ['\u{a68d}', '\u{0}', '\u{0}']), - ('\u{a68e}', ['\u{a68f}', '\u{0}', '\u{0}']), ('\u{a690}', ['\u{a691}', '\u{0}', '\u{0}']), - ('\u{a692}', ['\u{a693}', '\u{0}', '\u{0}']), ('\u{a694}', ['\u{a695}', '\u{0}', '\u{0}']), - ('\u{a696}', ['\u{a697}', '\u{0}', '\u{0}']), ('\u{a698}', ['\u{a699}', '\u{0}', '\u{0}']), - ('\u{a69a}', ['\u{a69b}', '\u{0}', '\u{0}']), ('\u{a722}', ['\u{a723}', '\u{0}', '\u{0}']), - ('\u{a724}', ['\u{a725}', '\u{0}', '\u{0}']), ('\u{a726}', ['\u{a727}', '\u{0}', '\u{0}']), - ('\u{a728}', ['\u{a729}', '\u{0}', '\u{0}']), ('\u{a72a}', ['\u{a72b}', '\u{0}', '\u{0}']), - ('\u{a72c}', ['\u{a72d}', '\u{0}', '\u{0}']), ('\u{a72e}', ['\u{a72f}', '\u{0}', '\u{0}']), - ('\u{a732}', ['\u{a733}', '\u{0}', '\u{0}']), ('\u{a734}', ['\u{a735}', '\u{0}', '\u{0}']), - ('\u{a736}', ['\u{a737}', '\u{0}', '\u{0}']), ('\u{a738}', ['\u{a739}', '\u{0}', '\u{0}']), - ('\u{a73a}', ['\u{a73b}', '\u{0}', '\u{0}']), ('\u{a73c}', ['\u{a73d}', '\u{0}', '\u{0}']), - ('\u{a73e}', ['\u{a73f}', '\u{0}', '\u{0}']), ('\u{a740}', ['\u{a741}', '\u{0}', '\u{0}']), - ('\u{a742}', ['\u{a743}', '\u{0}', '\u{0}']), ('\u{a744}', ['\u{a745}', '\u{0}', '\u{0}']), - ('\u{a746}', ['\u{a747}', '\u{0}', '\u{0}']), ('\u{a748}', ['\u{a749}', '\u{0}', '\u{0}']), - ('\u{a74a}', ['\u{a74b}', '\u{0}', '\u{0}']), ('\u{a74c}', ['\u{a74d}', '\u{0}', '\u{0}']), - ('\u{a74e}', ['\u{a74f}', '\u{0}', '\u{0}']), ('\u{a750}', ['\u{a751}', '\u{0}', '\u{0}']), - ('\u{a752}', ['\u{a753}', '\u{0}', '\u{0}']), ('\u{a754}', ['\u{a755}', '\u{0}', '\u{0}']), - ('\u{a756}', ['\u{a757}', '\u{0}', '\u{0}']), ('\u{a758}', ['\u{a759}', '\u{0}', '\u{0}']), - ('\u{a75a}', ['\u{a75b}', '\u{0}', '\u{0}']), ('\u{a75c}', ['\u{a75d}', '\u{0}', '\u{0}']), - ('\u{a75e}', ['\u{a75f}', '\u{0}', '\u{0}']), ('\u{a760}', ['\u{a761}', '\u{0}', '\u{0}']), - ('\u{a762}', ['\u{a763}', '\u{0}', '\u{0}']), ('\u{a764}', ['\u{a765}', '\u{0}', '\u{0}']), - ('\u{a766}', ['\u{a767}', '\u{0}', '\u{0}']), ('\u{a768}', ['\u{a769}', '\u{0}', '\u{0}']), - ('\u{a76a}', ['\u{a76b}', '\u{0}', '\u{0}']), ('\u{a76c}', ['\u{a76d}', '\u{0}', '\u{0}']), - ('\u{a76e}', ['\u{a76f}', '\u{0}', '\u{0}']), ('\u{a779}', ['\u{a77a}', '\u{0}', '\u{0}']), - ('\u{a77b}', ['\u{a77c}', '\u{0}', '\u{0}']), ('\u{a77d}', ['\u{1d79}', '\u{0}', '\u{0}']), - ('\u{a77e}', ['\u{a77f}', '\u{0}', '\u{0}']), ('\u{a780}', ['\u{a781}', '\u{0}', '\u{0}']), - ('\u{a782}', ['\u{a783}', '\u{0}', '\u{0}']), ('\u{a784}', ['\u{a785}', '\u{0}', '\u{0}']), - ('\u{a786}', ['\u{a787}', '\u{0}', '\u{0}']), ('\u{a78b}', ['\u{a78c}', '\u{0}', '\u{0}']), - ('\u{a78d}', ['\u{265}', '\u{0}', '\u{0}']), ('\u{a790}', ['\u{a791}', '\u{0}', '\u{0}']), - ('\u{a792}', ['\u{a793}', '\u{0}', '\u{0}']), ('\u{a796}', ['\u{a797}', '\u{0}', '\u{0}']), - ('\u{a798}', ['\u{a799}', '\u{0}', '\u{0}']), ('\u{a79a}', ['\u{a79b}', '\u{0}', '\u{0}']), - ('\u{a79c}', ['\u{a79d}', '\u{0}', '\u{0}']), ('\u{a79e}', ['\u{a79f}', '\u{0}', '\u{0}']), - ('\u{a7a0}', ['\u{a7a1}', '\u{0}', '\u{0}']), ('\u{a7a2}', ['\u{a7a3}', '\u{0}', '\u{0}']), - ('\u{a7a4}', ['\u{a7a5}', '\u{0}', '\u{0}']), ('\u{a7a6}', ['\u{a7a7}', '\u{0}', '\u{0}']), - ('\u{a7a8}', ['\u{a7a9}', '\u{0}', '\u{0}']), ('\u{a7aa}', ['\u{266}', '\u{0}', '\u{0}']), - ('\u{a7ab}', ['\u{25c}', '\u{0}', '\u{0}']), ('\u{a7ac}', ['\u{261}', '\u{0}', '\u{0}']), - ('\u{a7ad}', ['\u{26c}', '\u{0}', '\u{0}']), ('\u{a7ae}', ['\u{26a}', '\u{0}', '\u{0}']), - ('\u{a7b0}', ['\u{29e}', '\u{0}', '\u{0}']), ('\u{a7b1}', ['\u{287}', '\u{0}', '\u{0}']), - ('\u{a7b2}', ['\u{29d}', '\u{0}', '\u{0}']), ('\u{a7b3}', ['\u{ab53}', '\u{0}', '\u{0}']), - ('\u{a7b4}', ['\u{a7b5}', '\u{0}', '\u{0}']), ('\u{a7b6}', ['\u{a7b7}', '\u{0}', '\u{0}']), - ('\u{a7b8}', ['\u{a7b9}', '\u{0}', '\u{0}']), ('\u{a7ba}', ['\u{a7bb}', '\u{0}', '\u{0}']), - ('\u{a7bc}', ['\u{a7bd}', '\u{0}', '\u{0}']), ('\u{a7be}', ['\u{a7bf}', '\u{0}', '\u{0}']), - ('\u{a7c0}', ['\u{a7c1}', '\u{0}', '\u{0}']), ('\u{a7c2}', ['\u{a7c3}', '\u{0}', '\u{0}']), - ('\u{a7c4}', ['\u{a794}', '\u{0}', '\u{0}']), ('\u{a7c5}', ['\u{282}', '\u{0}', '\u{0}']), - ('\u{a7c6}', ['\u{1d8e}', '\u{0}', '\u{0}']), ('\u{a7c7}', ['\u{a7c8}', '\u{0}', '\u{0}']), - ('\u{a7c9}', ['\u{a7ca}', '\u{0}', '\u{0}']), ('\u{a7d0}', ['\u{a7d1}', '\u{0}', '\u{0}']), - ('\u{a7d6}', ['\u{a7d7}', '\u{0}', '\u{0}']), ('\u{a7d8}', ['\u{a7d9}', '\u{0}', '\u{0}']), - ('\u{a7f5}', ['\u{a7f6}', '\u{0}', '\u{0}']), ('\u{ff21}', ['\u{ff41}', '\u{0}', '\u{0}']), - ('\u{ff22}', ['\u{ff42}', '\u{0}', '\u{0}']), ('\u{ff23}', ['\u{ff43}', '\u{0}', '\u{0}']), - ('\u{ff24}', ['\u{ff44}', '\u{0}', '\u{0}']), ('\u{ff25}', ['\u{ff45}', '\u{0}', '\u{0}']), - ('\u{ff26}', ['\u{ff46}', '\u{0}', '\u{0}']), ('\u{ff27}', ['\u{ff47}', '\u{0}', '\u{0}']), - ('\u{ff28}', ['\u{ff48}', '\u{0}', '\u{0}']), ('\u{ff29}', ['\u{ff49}', '\u{0}', '\u{0}']), - ('\u{ff2a}', ['\u{ff4a}', '\u{0}', '\u{0}']), ('\u{ff2b}', ['\u{ff4b}', '\u{0}', '\u{0}']), - ('\u{ff2c}', ['\u{ff4c}', '\u{0}', '\u{0}']), ('\u{ff2d}', ['\u{ff4d}', '\u{0}', '\u{0}']), - ('\u{ff2e}', ['\u{ff4e}', '\u{0}', '\u{0}']), ('\u{ff2f}', ['\u{ff4f}', '\u{0}', '\u{0}']), - ('\u{ff30}', ['\u{ff50}', '\u{0}', '\u{0}']), ('\u{ff31}', ['\u{ff51}', '\u{0}', '\u{0}']), - ('\u{ff32}', ['\u{ff52}', '\u{0}', '\u{0}']), ('\u{ff33}', ['\u{ff53}', '\u{0}', '\u{0}']), - ('\u{ff34}', ['\u{ff54}', '\u{0}', '\u{0}']), ('\u{ff35}', ['\u{ff55}', '\u{0}', '\u{0}']), - ('\u{ff36}', ['\u{ff56}', '\u{0}', '\u{0}']), ('\u{ff37}', ['\u{ff57}', '\u{0}', '\u{0}']), - ('\u{ff38}', ['\u{ff58}', '\u{0}', '\u{0}']), ('\u{ff39}', ['\u{ff59}', '\u{0}', '\u{0}']), - ('\u{ff3a}', ['\u{ff5a}', '\u{0}', '\u{0}']), - ('\u{10400}', ['\u{10428}', '\u{0}', '\u{0}']), - ('\u{10401}', ['\u{10429}', '\u{0}', '\u{0}']), - ('\u{10402}', ['\u{1042a}', '\u{0}', '\u{0}']), - ('\u{10403}', ['\u{1042b}', '\u{0}', '\u{0}']), - ('\u{10404}', ['\u{1042c}', '\u{0}', '\u{0}']), - ('\u{10405}', ['\u{1042d}', '\u{0}', '\u{0}']), - ('\u{10406}', ['\u{1042e}', '\u{0}', '\u{0}']), - ('\u{10407}', ['\u{1042f}', '\u{0}', '\u{0}']), - ('\u{10408}', ['\u{10430}', '\u{0}', '\u{0}']), - ('\u{10409}', ['\u{10431}', '\u{0}', '\u{0}']), - ('\u{1040a}', ['\u{10432}', '\u{0}', '\u{0}']), - ('\u{1040b}', ['\u{10433}', '\u{0}', '\u{0}']), - ('\u{1040c}', ['\u{10434}', '\u{0}', '\u{0}']), - ('\u{1040d}', ['\u{10435}', '\u{0}', '\u{0}']), - ('\u{1040e}', ['\u{10436}', '\u{0}', '\u{0}']), - ('\u{1040f}', ['\u{10437}', '\u{0}', '\u{0}']), - ('\u{10410}', ['\u{10438}', '\u{0}', '\u{0}']), - ('\u{10411}', ['\u{10439}', '\u{0}', '\u{0}']), - ('\u{10412}', ['\u{1043a}', '\u{0}', '\u{0}']), - ('\u{10413}', ['\u{1043b}', '\u{0}', '\u{0}']), - ('\u{10414}', ['\u{1043c}', '\u{0}', '\u{0}']), - ('\u{10415}', ['\u{1043d}', '\u{0}', '\u{0}']), - ('\u{10416}', ['\u{1043e}', '\u{0}', '\u{0}']), - ('\u{10417}', ['\u{1043f}', '\u{0}', '\u{0}']), - ('\u{10418}', ['\u{10440}', '\u{0}', '\u{0}']), - ('\u{10419}', ['\u{10441}', '\u{0}', '\u{0}']), - ('\u{1041a}', ['\u{10442}', '\u{0}', '\u{0}']), - ('\u{1041b}', ['\u{10443}', '\u{0}', '\u{0}']), - ('\u{1041c}', ['\u{10444}', '\u{0}', '\u{0}']), - ('\u{1041d}', ['\u{10445}', '\u{0}', '\u{0}']), - ('\u{1041e}', ['\u{10446}', '\u{0}', '\u{0}']), - ('\u{1041f}', ['\u{10447}', '\u{0}', '\u{0}']), - ('\u{10420}', ['\u{10448}', '\u{0}', '\u{0}']), - ('\u{10421}', ['\u{10449}', '\u{0}', '\u{0}']), - ('\u{10422}', ['\u{1044a}', '\u{0}', '\u{0}']), - ('\u{10423}', ['\u{1044b}', '\u{0}', '\u{0}']), - ('\u{10424}', ['\u{1044c}', '\u{0}', '\u{0}']), - ('\u{10425}', ['\u{1044d}', '\u{0}', '\u{0}']), - ('\u{10426}', ['\u{1044e}', '\u{0}', '\u{0}']), - ('\u{10427}', ['\u{1044f}', '\u{0}', '\u{0}']), - ('\u{104b0}', ['\u{104d8}', '\u{0}', '\u{0}']), - ('\u{104b1}', ['\u{104d9}', '\u{0}', '\u{0}']), - ('\u{104b2}', ['\u{104da}', '\u{0}', '\u{0}']), - ('\u{104b3}', ['\u{104db}', '\u{0}', '\u{0}']), - ('\u{104b4}', ['\u{104dc}', '\u{0}', '\u{0}']), - ('\u{104b5}', ['\u{104dd}', '\u{0}', '\u{0}']), - ('\u{104b6}', ['\u{104de}', '\u{0}', '\u{0}']), - ('\u{104b7}', ['\u{104df}', '\u{0}', '\u{0}']), - ('\u{104b8}', ['\u{104e0}', '\u{0}', '\u{0}']), - ('\u{104b9}', ['\u{104e1}', '\u{0}', '\u{0}']), - ('\u{104ba}', ['\u{104e2}', '\u{0}', '\u{0}']), - ('\u{104bb}', ['\u{104e3}', '\u{0}', '\u{0}']), - ('\u{104bc}', ['\u{104e4}', '\u{0}', '\u{0}']), - ('\u{104bd}', ['\u{104e5}', '\u{0}', '\u{0}']), - ('\u{104be}', ['\u{104e6}', '\u{0}', '\u{0}']), - ('\u{104bf}', ['\u{104e7}', '\u{0}', '\u{0}']), - ('\u{104c0}', ['\u{104e8}', '\u{0}', '\u{0}']), - ('\u{104c1}', ['\u{104e9}', '\u{0}', '\u{0}']), - ('\u{104c2}', ['\u{104ea}', '\u{0}', '\u{0}']), - ('\u{104c3}', ['\u{104eb}', '\u{0}', '\u{0}']), - ('\u{104c4}', ['\u{104ec}', '\u{0}', '\u{0}']), - ('\u{104c5}', ['\u{104ed}', '\u{0}', '\u{0}']), - ('\u{104c6}', ['\u{104ee}', '\u{0}', '\u{0}']), - ('\u{104c7}', ['\u{104ef}', '\u{0}', '\u{0}']), - ('\u{104c8}', ['\u{104f0}', '\u{0}', '\u{0}']), - ('\u{104c9}', ['\u{104f1}', '\u{0}', '\u{0}']), - ('\u{104ca}', ['\u{104f2}', '\u{0}', '\u{0}']), - ('\u{104cb}', ['\u{104f3}', '\u{0}', '\u{0}']), - ('\u{104cc}', ['\u{104f4}', '\u{0}', '\u{0}']), - ('\u{104cd}', ['\u{104f5}', '\u{0}', '\u{0}']), - ('\u{104ce}', ['\u{104f6}', '\u{0}', '\u{0}']), - ('\u{104cf}', ['\u{104f7}', '\u{0}', '\u{0}']), - ('\u{104d0}', ['\u{104f8}', '\u{0}', '\u{0}']), - ('\u{104d1}', ['\u{104f9}', '\u{0}', '\u{0}']), - ('\u{104d2}', ['\u{104fa}', '\u{0}', '\u{0}']), - ('\u{104d3}', ['\u{104fb}', '\u{0}', '\u{0}']), - ('\u{10570}', ['\u{10597}', '\u{0}', '\u{0}']), - ('\u{10571}', ['\u{10598}', '\u{0}', '\u{0}']), - ('\u{10572}', ['\u{10599}', '\u{0}', '\u{0}']), - ('\u{10573}', ['\u{1059a}', '\u{0}', '\u{0}']), - ('\u{10574}', ['\u{1059b}', '\u{0}', '\u{0}']), - ('\u{10575}', ['\u{1059c}', '\u{0}', '\u{0}']), - ('\u{10576}', ['\u{1059d}', '\u{0}', '\u{0}']), - ('\u{10577}', ['\u{1059e}', '\u{0}', '\u{0}']), - ('\u{10578}', ['\u{1059f}', '\u{0}', '\u{0}']), - ('\u{10579}', ['\u{105a0}', '\u{0}', '\u{0}']), - ('\u{1057a}', ['\u{105a1}', '\u{0}', '\u{0}']), - ('\u{1057c}', ['\u{105a3}', '\u{0}', '\u{0}']), - ('\u{1057d}', ['\u{105a4}', '\u{0}', '\u{0}']), - ('\u{1057e}', ['\u{105a5}', '\u{0}', '\u{0}']), - ('\u{1057f}', ['\u{105a6}', '\u{0}', '\u{0}']), - ('\u{10580}', ['\u{105a7}', '\u{0}', '\u{0}']), - ('\u{10581}', ['\u{105a8}', '\u{0}', '\u{0}']), - ('\u{10582}', ['\u{105a9}', '\u{0}', '\u{0}']), - ('\u{10583}', ['\u{105aa}', '\u{0}', '\u{0}']), - ('\u{10584}', ['\u{105ab}', '\u{0}', '\u{0}']), - ('\u{10585}', ['\u{105ac}', '\u{0}', '\u{0}']), - ('\u{10586}', ['\u{105ad}', '\u{0}', '\u{0}']), - ('\u{10587}', ['\u{105ae}', '\u{0}', '\u{0}']), - ('\u{10588}', ['\u{105af}', '\u{0}', '\u{0}']), - ('\u{10589}', ['\u{105b0}', '\u{0}', '\u{0}']), - ('\u{1058a}', ['\u{105b1}', '\u{0}', '\u{0}']), - ('\u{1058c}', ['\u{105b3}', '\u{0}', '\u{0}']), - ('\u{1058d}', ['\u{105b4}', '\u{0}', '\u{0}']), - ('\u{1058e}', ['\u{105b5}', '\u{0}', '\u{0}']), - ('\u{1058f}', ['\u{105b6}', '\u{0}', '\u{0}']), - ('\u{10590}', ['\u{105b7}', '\u{0}', '\u{0}']), - ('\u{10591}', ['\u{105b8}', '\u{0}', '\u{0}']), - ('\u{10592}', ['\u{105b9}', '\u{0}', '\u{0}']), - ('\u{10594}', ['\u{105bb}', '\u{0}', '\u{0}']), - ('\u{10595}', ['\u{105bc}', '\u{0}', '\u{0}']), - ('\u{10c80}', ['\u{10cc0}', '\u{0}', '\u{0}']), - ('\u{10c81}', ['\u{10cc1}', '\u{0}', '\u{0}']), - ('\u{10c82}', ['\u{10cc2}', '\u{0}', '\u{0}']), - ('\u{10c83}', ['\u{10cc3}', '\u{0}', '\u{0}']), - ('\u{10c84}', ['\u{10cc4}', '\u{0}', '\u{0}']), - ('\u{10c85}', ['\u{10cc5}', '\u{0}', '\u{0}']), - ('\u{10c86}', ['\u{10cc6}', '\u{0}', '\u{0}']), - ('\u{10c87}', ['\u{10cc7}', '\u{0}', '\u{0}']), - ('\u{10c88}', ['\u{10cc8}', '\u{0}', '\u{0}']), - ('\u{10c89}', ['\u{10cc9}', '\u{0}', '\u{0}']), - ('\u{10c8a}', ['\u{10cca}', '\u{0}', '\u{0}']), - ('\u{10c8b}', ['\u{10ccb}', '\u{0}', '\u{0}']), - ('\u{10c8c}', ['\u{10ccc}', '\u{0}', '\u{0}']), - ('\u{10c8d}', ['\u{10ccd}', '\u{0}', '\u{0}']), - ('\u{10c8e}', ['\u{10cce}', '\u{0}', '\u{0}']), - ('\u{10c8f}', ['\u{10ccf}', '\u{0}', '\u{0}']), - ('\u{10c90}', ['\u{10cd0}', '\u{0}', '\u{0}']), - ('\u{10c91}', ['\u{10cd1}', '\u{0}', '\u{0}']), - ('\u{10c92}', ['\u{10cd2}', '\u{0}', '\u{0}']), - ('\u{10c93}', ['\u{10cd3}', '\u{0}', '\u{0}']), - ('\u{10c94}', ['\u{10cd4}', '\u{0}', '\u{0}']), - ('\u{10c95}', ['\u{10cd5}', '\u{0}', '\u{0}']), - ('\u{10c96}', ['\u{10cd6}', '\u{0}', '\u{0}']), - ('\u{10c97}', ['\u{10cd7}', '\u{0}', '\u{0}']), - ('\u{10c98}', ['\u{10cd8}', '\u{0}', '\u{0}']), - ('\u{10c99}', ['\u{10cd9}', '\u{0}', '\u{0}']), - ('\u{10c9a}', ['\u{10cda}', '\u{0}', '\u{0}']), - ('\u{10c9b}', ['\u{10cdb}', '\u{0}', '\u{0}']), - ('\u{10c9c}', ['\u{10cdc}', '\u{0}', '\u{0}']), - ('\u{10c9d}', ['\u{10cdd}', '\u{0}', '\u{0}']), - ('\u{10c9e}', ['\u{10cde}', '\u{0}', '\u{0}']), - ('\u{10c9f}', ['\u{10cdf}', '\u{0}', '\u{0}']), - ('\u{10ca0}', ['\u{10ce0}', '\u{0}', '\u{0}']), - ('\u{10ca1}', ['\u{10ce1}', '\u{0}', '\u{0}']), - ('\u{10ca2}', ['\u{10ce2}', '\u{0}', '\u{0}']), - ('\u{10ca3}', ['\u{10ce3}', '\u{0}', '\u{0}']), - ('\u{10ca4}', ['\u{10ce4}', '\u{0}', '\u{0}']), - ('\u{10ca5}', ['\u{10ce5}', '\u{0}', '\u{0}']), - ('\u{10ca6}', ['\u{10ce6}', '\u{0}', '\u{0}']), - ('\u{10ca7}', ['\u{10ce7}', '\u{0}', '\u{0}']), - ('\u{10ca8}', ['\u{10ce8}', '\u{0}', '\u{0}']), - ('\u{10ca9}', ['\u{10ce9}', '\u{0}', '\u{0}']), - ('\u{10caa}', ['\u{10cea}', '\u{0}', '\u{0}']), - ('\u{10cab}', ['\u{10ceb}', '\u{0}', '\u{0}']), - ('\u{10cac}', ['\u{10cec}', '\u{0}', '\u{0}']), - ('\u{10cad}', ['\u{10ced}', '\u{0}', '\u{0}']), - ('\u{10cae}', ['\u{10cee}', '\u{0}', '\u{0}']), - ('\u{10caf}', ['\u{10cef}', '\u{0}', '\u{0}']), - ('\u{10cb0}', ['\u{10cf0}', '\u{0}', '\u{0}']), - ('\u{10cb1}', ['\u{10cf1}', '\u{0}', '\u{0}']), - ('\u{10cb2}', ['\u{10cf2}', '\u{0}', '\u{0}']), - ('\u{118a0}', ['\u{118c0}', '\u{0}', '\u{0}']), - ('\u{118a1}', ['\u{118c1}', '\u{0}', '\u{0}']), - ('\u{118a2}', ['\u{118c2}', '\u{0}', '\u{0}']), - ('\u{118a3}', ['\u{118c3}', '\u{0}', '\u{0}']), - ('\u{118a4}', ['\u{118c4}', '\u{0}', '\u{0}']), - ('\u{118a5}', ['\u{118c5}', '\u{0}', '\u{0}']), - ('\u{118a6}', ['\u{118c6}', '\u{0}', '\u{0}']), - ('\u{118a7}', ['\u{118c7}', '\u{0}', '\u{0}']), - ('\u{118a8}', ['\u{118c8}', '\u{0}', '\u{0}']), - ('\u{118a9}', ['\u{118c9}', '\u{0}', '\u{0}']), - ('\u{118aa}', ['\u{118ca}', '\u{0}', '\u{0}']), - ('\u{118ab}', ['\u{118cb}', '\u{0}', '\u{0}']), - ('\u{118ac}', ['\u{118cc}', '\u{0}', '\u{0}']), - ('\u{118ad}', ['\u{118cd}', '\u{0}', '\u{0}']), - ('\u{118ae}', ['\u{118ce}', '\u{0}', '\u{0}']), - ('\u{118af}', ['\u{118cf}', '\u{0}', '\u{0}']), - ('\u{118b0}', ['\u{118d0}', '\u{0}', '\u{0}']), - ('\u{118b1}', ['\u{118d1}', '\u{0}', '\u{0}']), - ('\u{118b2}', ['\u{118d2}', '\u{0}', '\u{0}']), - ('\u{118b3}', ['\u{118d3}', '\u{0}', '\u{0}']), - ('\u{118b4}', ['\u{118d4}', '\u{0}', '\u{0}']), - ('\u{118b5}', ['\u{118d5}', '\u{0}', '\u{0}']), - ('\u{118b6}', ['\u{118d6}', '\u{0}', '\u{0}']), - ('\u{118b7}', ['\u{118d7}', '\u{0}', '\u{0}']), - ('\u{118b8}', ['\u{118d8}', '\u{0}', '\u{0}']), - ('\u{118b9}', ['\u{118d9}', '\u{0}', '\u{0}']), - ('\u{118ba}', ['\u{118da}', '\u{0}', '\u{0}']), - ('\u{118bb}', ['\u{118db}', '\u{0}', '\u{0}']), - ('\u{118bc}', ['\u{118dc}', '\u{0}', '\u{0}']), - ('\u{118bd}', ['\u{118dd}', '\u{0}', '\u{0}']), - ('\u{118be}', ['\u{118de}', '\u{0}', '\u{0}']), - ('\u{118bf}', ['\u{118df}', '\u{0}', '\u{0}']), - ('\u{16e40}', ['\u{16e60}', '\u{0}', '\u{0}']), - ('\u{16e41}', ['\u{16e61}', '\u{0}', '\u{0}']), - ('\u{16e42}', ['\u{16e62}', '\u{0}', '\u{0}']), - ('\u{16e43}', ['\u{16e63}', '\u{0}', '\u{0}']), - ('\u{16e44}', ['\u{16e64}', '\u{0}', '\u{0}']), - ('\u{16e45}', ['\u{16e65}', '\u{0}', '\u{0}']), - ('\u{16e46}', ['\u{16e66}', '\u{0}', '\u{0}']), - ('\u{16e47}', ['\u{16e67}', '\u{0}', '\u{0}']), - ('\u{16e48}', ['\u{16e68}', '\u{0}', '\u{0}']), - ('\u{16e49}', ['\u{16e69}', '\u{0}', '\u{0}']), - ('\u{16e4a}', ['\u{16e6a}', '\u{0}', '\u{0}']), - ('\u{16e4b}', ['\u{16e6b}', '\u{0}', '\u{0}']), - ('\u{16e4c}', ['\u{16e6c}', '\u{0}', '\u{0}']), - ('\u{16e4d}', ['\u{16e6d}', '\u{0}', '\u{0}']), - ('\u{16e4e}', ['\u{16e6e}', '\u{0}', '\u{0}']), - ('\u{16e4f}', ['\u{16e6f}', '\u{0}', '\u{0}']), - ('\u{16e50}', ['\u{16e70}', '\u{0}', '\u{0}']), - ('\u{16e51}', ['\u{16e71}', '\u{0}', '\u{0}']), - ('\u{16e52}', ['\u{16e72}', '\u{0}', '\u{0}']), - ('\u{16e53}', ['\u{16e73}', '\u{0}', '\u{0}']), - ('\u{16e54}', ['\u{16e74}', '\u{0}', '\u{0}']), - ('\u{16e55}', ['\u{16e75}', '\u{0}', '\u{0}']), - ('\u{16e56}', ['\u{16e76}', '\u{0}', '\u{0}']), - ('\u{16e57}', ['\u{16e77}', '\u{0}', '\u{0}']), - ('\u{16e58}', ['\u{16e78}', '\u{0}', '\u{0}']), - ('\u{16e59}', ['\u{16e79}', '\u{0}', '\u{0}']), - ('\u{16e5a}', ['\u{16e7a}', '\u{0}', '\u{0}']), - ('\u{16e5b}', ['\u{16e7b}', '\u{0}', '\u{0}']), - ('\u{16e5c}', ['\u{16e7c}', '\u{0}', '\u{0}']), - ('\u{16e5d}', ['\u{16e7d}', '\u{0}', '\u{0}']), - ('\u{16e5e}', ['\u{16e7e}', '\u{0}', '\u{0}']), - ('\u{16e5f}', ['\u{16e7f}', '\u{0}', '\u{0}']), - ('\u{1e900}', ['\u{1e922}', '\u{0}', '\u{0}']), - ('\u{1e901}', ['\u{1e923}', '\u{0}', '\u{0}']), - ('\u{1e902}', ['\u{1e924}', '\u{0}', '\u{0}']), - ('\u{1e903}', ['\u{1e925}', '\u{0}', '\u{0}']), - ('\u{1e904}', ['\u{1e926}', '\u{0}', '\u{0}']), - ('\u{1e905}', ['\u{1e927}', '\u{0}', '\u{0}']), - ('\u{1e906}', ['\u{1e928}', '\u{0}', '\u{0}']), - ('\u{1e907}', ['\u{1e929}', '\u{0}', '\u{0}']), - ('\u{1e908}', ['\u{1e92a}', '\u{0}', '\u{0}']), - ('\u{1e909}', ['\u{1e92b}', '\u{0}', '\u{0}']), - ('\u{1e90a}', ['\u{1e92c}', '\u{0}', '\u{0}']), - ('\u{1e90b}', ['\u{1e92d}', '\u{0}', '\u{0}']), - ('\u{1e90c}', ['\u{1e92e}', '\u{0}', '\u{0}']), - ('\u{1e90d}', ['\u{1e92f}', '\u{0}', '\u{0}']), - ('\u{1e90e}', ['\u{1e930}', '\u{0}', '\u{0}']), - ('\u{1e90f}', ['\u{1e931}', '\u{0}', '\u{0}']), - ('\u{1e910}', ['\u{1e932}', '\u{0}', '\u{0}']), - ('\u{1e911}', ['\u{1e933}', '\u{0}', '\u{0}']), - ('\u{1e912}', ['\u{1e934}', '\u{0}', '\u{0}']), - ('\u{1e913}', ['\u{1e935}', '\u{0}', '\u{0}']), - ('\u{1e914}', ['\u{1e936}', '\u{0}', '\u{0}']), - ('\u{1e915}', ['\u{1e937}', '\u{0}', '\u{0}']), - ('\u{1e916}', ['\u{1e938}', '\u{0}', '\u{0}']), - ('\u{1e917}', ['\u{1e939}', '\u{0}', '\u{0}']), - ('\u{1e918}', ['\u{1e93a}', '\u{0}', '\u{0}']), - ('\u{1e919}', ['\u{1e93b}', '\u{0}', '\u{0}']), - ('\u{1e91a}', ['\u{1e93c}', '\u{0}', '\u{0}']), - ('\u{1e91b}', ['\u{1e93d}', '\u{0}', '\u{0}']), - ('\u{1e91c}', ['\u{1e93e}', '\u{0}', '\u{0}']), - ('\u{1e91d}', ['\u{1e93f}', '\u{0}', '\u{0}']), - ('\u{1e91e}', ['\u{1e940}', '\u{0}', '\u{0}']), - ('\u{1e91f}', ['\u{1e941}', '\u{0}', '\u{0}']), - ('\u{1e920}', ['\u{1e942}', '\u{0}', '\u{0}']), - ('\u{1e921}', ['\u{1e943}', '\u{0}', '\u{0}']), + static LOWERCASE_TABLE: &[(char, u32)] = &[ + ('\u{c0}', 224), ('\u{c1}', 225), ('\u{c2}', 226), ('\u{c3}', 227), ('\u{c4}', 228), + ('\u{c5}', 229), ('\u{c6}', 230), ('\u{c7}', 231), ('\u{c8}', 232), ('\u{c9}', 233), + ('\u{ca}', 234), ('\u{cb}', 235), ('\u{cc}', 236), ('\u{cd}', 237), ('\u{ce}', 238), + ('\u{cf}', 239), ('\u{d0}', 240), ('\u{d1}', 241), ('\u{d2}', 242), ('\u{d3}', 243), + ('\u{d4}', 244), ('\u{d5}', 245), ('\u{d6}', 246), ('\u{d8}', 248), ('\u{d9}', 249), + ('\u{da}', 250), ('\u{db}', 251), ('\u{dc}', 252), ('\u{dd}', 253), ('\u{de}', 254), + ('\u{100}', 257), ('\u{102}', 259), ('\u{104}', 261), ('\u{106}', 263), ('\u{108}', 265), + ('\u{10a}', 267), ('\u{10c}', 269), ('\u{10e}', 271), ('\u{110}', 273), ('\u{112}', 275), + ('\u{114}', 277), ('\u{116}', 279), ('\u{118}', 281), ('\u{11a}', 283), ('\u{11c}', 285), + ('\u{11e}', 287), ('\u{120}', 289), ('\u{122}', 291), ('\u{124}', 293), ('\u{126}', 295), + ('\u{128}', 297), ('\u{12a}', 299), ('\u{12c}', 301), ('\u{12e}', 303), + ('\u{130}', 4194304), ('\u{132}', 307), ('\u{134}', 309), ('\u{136}', 311), + ('\u{139}', 314), ('\u{13b}', 316), ('\u{13d}', 318), ('\u{13f}', 320), ('\u{141}', 322), + ('\u{143}', 324), ('\u{145}', 326), ('\u{147}', 328), ('\u{14a}', 331), ('\u{14c}', 333), + ('\u{14e}', 335), ('\u{150}', 337), ('\u{152}', 339), ('\u{154}', 341), ('\u{156}', 343), + ('\u{158}', 345), ('\u{15a}', 347), ('\u{15c}', 349), ('\u{15e}', 351), ('\u{160}', 353), + ('\u{162}', 355), ('\u{164}', 357), ('\u{166}', 359), ('\u{168}', 361), ('\u{16a}', 363), + ('\u{16c}', 365), ('\u{16e}', 367), ('\u{170}', 369), ('\u{172}', 371), ('\u{174}', 373), + ('\u{176}', 375), ('\u{178}', 255), ('\u{179}', 378), ('\u{17b}', 380), ('\u{17d}', 382), + ('\u{181}', 595), ('\u{182}', 387), ('\u{184}', 389), ('\u{186}', 596), ('\u{187}', 392), + ('\u{189}', 598), ('\u{18a}', 599), ('\u{18b}', 396), ('\u{18e}', 477), ('\u{18f}', 601), + ('\u{190}', 603), ('\u{191}', 402), ('\u{193}', 608), ('\u{194}', 611), ('\u{196}', 617), + ('\u{197}', 616), ('\u{198}', 409), ('\u{19c}', 623), ('\u{19d}', 626), ('\u{19f}', 629), + ('\u{1a0}', 417), ('\u{1a2}', 419), ('\u{1a4}', 421), ('\u{1a6}', 640), ('\u{1a7}', 424), + ('\u{1a9}', 643), ('\u{1ac}', 429), ('\u{1ae}', 648), ('\u{1af}', 432), ('\u{1b1}', 650), + ('\u{1b2}', 651), ('\u{1b3}', 436), ('\u{1b5}', 438), ('\u{1b7}', 658), ('\u{1b8}', 441), + ('\u{1bc}', 445), ('\u{1c4}', 454), ('\u{1c5}', 454), ('\u{1c7}', 457), ('\u{1c8}', 457), + ('\u{1ca}', 460), ('\u{1cb}', 460), ('\u{1cd}', 462), ('\u{1cf}', 464), ('\u{1d1}', 466), + ('\u{1d3}', 468), ('\u{1d5}', 470), ('\u{1d7}', 472), ('\u{1d9}', 474), ('\u{1db}', 476), + ('\u{1de}', 479), ('\u{1e0}', 481), ('\u{1e2}', 483), ('\u{1e4}', 485), ('\u{1e6}', 487), + ('\u{1e8}', 489), ('\u{1ea}', 491), ('\u{1ec}', 493), ('\u{1ee}', 495), ('\u{1f1}', 499), + ('\u{1f2}', 499), ('\u{1f4}', 501), ('\u{1f6}', 405), ('\u{1f7}', 447), ('\u{1f8}', 505), + ('\u{1fa}', 507), ('\u{1fc}', 509), ('\u{1fe}', 511), ('\u{200}', 513), ('\u{202}', 515), + ('\u{204}', 517), ('\u{206}', 519), ('\u{208}', 521), ('\u{20a}', 523), ('\u{20c}', 525), + ('\u{20e}', 527), ('\u{210}', 529), ('\u{212}', 531), ('\u{214}', 533), ('\u{216}', 535), + ('\u{218}', 537), ('\u{21a}', 539), ('\u{21c}', 541), ('\u{21e}', 543), ('\u{220}', 414), + ('\u{222}', 547), ('\u{224}', 549), ('\u{226}', 551), ('\u{228}', 553), ('\u{22a}', 555), + ('\u{22c}', 557), ('\u{22e}', 559), ('\u{230}', 561), ('\u{232}', 563), ('\u{23a}', 11365), + ('\u{23b}', 572), ('\u{23d}', 410), ('\u{23e}', 11366), ('\u{241}', 578), ('\u{243}', 384), + ('\u{244}', 649), ('\u{245}', 652), ('\u{246}', 583), ('\u{248}', 585), ('\u{24a}', 587), + ('\u{24c}', 589), ('\u{24e}', 591), ('\u{370}', 881), ('\u{372}', 883), ('\u{376}', 887), + ('\u{37f}', 1011), ('\u{386}', 940), ('\u{388}', 941), ('\u{389}', 942), ('\u{38a}', 943), + ('\u{38c}', 972), ('\u{38e}', 973), ('\u{38f}', 974), ('\u{391}', 945), ('\u{392}', 946), + ('\u{393}', 947), ('\u{394}', 948), ('\u{395}', 949), ('\u{396}', 950), ('\u{397}', 951), + ('\u{398}', 952), ('\u{399}', 953), ('\u{39a}', 954), ('\u{39b}', 955), ('\u{39c}', 956), + ('\u{39d}', 957), ('\u{39e}', 958), ('\u{39f}', 959), ('\u{3a0}', 960), ('\u{3a1}', 961), + ('\u{3a3}', 963), ('\u{3a4}', 964), ('\u{3a5}', 965), ('\u{3a6}', 966), ('\u{3a7}', 967), + ('\u{3a8}', 968), ('\u{3a9}', 969), ('\u{3aa}', 970), ('\u{3ab}', 971), ('\u{3cf}', 983), + ('\u{3d8}', 985), ('\u{3da}', 987), ('\u{3dc}', 989), ('\u{3de}', 991), ('\u{3e0}', 993), + ('\u{3e2}', 995), ('\u{3e4}', 997), ('\u{3e6}', 999), ('\u{3e8}', 1001), ('\u{3ea}', 1003), + ('\u{3ec}', 1005), ('\u{3ee}', 1007), ('\u{3f4}', 952), ('\u{3f7}', 1016), + ('\u{3f9}', 1010), ('\u{3fa}', 1019), ('\u{3fd}', 891), ('\u{3fe}', 892), ('\u{3ff}', 893), + ('\u{400}', 1104), ('\u{401}', 1105), ('\u{402}', 1106), ('\u{403}', 1107), + ('\u{404}', 1108), ('\u{405}', 1109), ('\u{406}', 1110), ('\u{407}', 1111), + ('\u{408}', 1112), ('\u{409}', 1113), ('\u{40a}', 1114), ('\u{40b}', 1115), + ('\u{40c}', 1116), ('\u{40d}', 1117), ('\u{40e}', 1118), ('\u{40f}', 1119), + ('\u{410}', 1072), ('\u{411}', 1073), ('\u{412}', 1074), ('\u{413}', 1075), + ('\u{414}', 1076), ('\u{415}', 1077), ('\u{416}', 1078), ('\u{417}', 1079), + ('\u{418}', 1080), ('\u{419}', 1081), ('\u{41a}', 1082), ('\u{41b}', 1083), + ('\u{41c}', 1084), ('\u{41d}', 1085), ('\u{41e}', 1086), ('\u{41f}', 1087), + ('\u{420}', 1088), ('\u{421}', 1089), ('\u{422}', 1090), ('\u{423}', 1091), + ('\u{424}', 1092), ('\u{425}', 1093), ('\u{426}', 1094), ('\u{427}', 1095), + ('\u{428}', 1096), ('\u{429}', 1097), ('\u{42a}', 1098), ('\u{42b}', 1099), + ('\u{42c}', 1100), ('\u{42d}', 1101), ('\u{42e}', 1102), ('\u{42f}', 1103), + ('\u{460}', 1121), ('\u{462}', 1123), ('\u{464}', 1125), ('\u{466}', 1127), + ('\u{468}', 1129), ('\u{46a}', 1131), ('\u{46c}', 1133), ('\u{46e}', 1135), + ('\u{470}', 1137), ('\u{472}', 1139), ('\u{474}', 1141), ('\u{476}', 1143), + ('\u{478}', 1145), ('\u{47a}', 1147), ('\u{47c}', 1149), ('\u{47e}', 1151), + ('\u{480}', 1153), ('\u{48a}', 1163), ('\u{48c}', 1165), ('\u{48e}', 1167), + ('\u{490}', 1169), ('\u{492}', 1171), ('\u{494}', 1173), ('\u{496}', 1175), + ('\u{498}', 1177), ('\u{49a}', 1179), ('\u{49c}', 1181), ('\u{49e}', 1183), + ('\u{4a0}', 1185), ('\u{4a2}', 1187), ('\u{4a4}', 1189), ('\u{4a6}', 1191), + ('\u{4a8}', 1193), ('\u{4aa}', 1195), ('\u{4ac}', 1197), ('\u{4ae}', 1199), + ('\u{4b0}', 1201), ('\u{4b2}', 1203), ('\u{4b4}', 1205), ('\u{4b6}', 1207), + ('\u{4b8}', 1209), ('\u{4ba}', 1211), ('\u{4bc}', 1213), ('\u{4be}', 1215), + ('\u{4c0}', 1231), ('\u{4c1}', 1218), ('\u{4c3}', 1220), ('\u{4c5}', 1222), + ('\u{4c7}', 1224), ('\u{4c9}', 1226), ('\u{4cb}', 1228), ('\u{4cd}', 1230), + ('\u{4d0}', 1233), ('\u{4d2}', 1235), ('\u{4d4}', 1237), ('\u{4d6}', 1239), + ('\u{4d8}', 1241), ('\u{4da}', 1243), ('\u{4dc}', 1245), ('\u{4de}', 1247), + ('\u{4e0}', 1249), ('\u{4e2}', 1251), ('\u{4e4}', 1253), ('\u{4e6}', 1255), + ('\u{4e8}', 1257), ('\u{4ea}', 1259), ('\u{4ec}', 1261), ('\u{4ee}', 1263), + ('\u{4f0}', 1265), ('\u{4f2}', 1267), ('\u{4f4}', 1269), ('\u{4f6}', 1271), + ('\u{4f8}', 1273), ('\u{4fa}', 1275), ('\u{4fc}', 1277), ('\u{4fe}', 1279), + ('\u{500}', 1281), ('\u{502}', 1283), ('\u{504}', 1285), ('\u{506}', 1287), + ('\u{508}', 1289), ('\u{50a}', 1291), ('\u{50c}', 1293), ('\u{50e}', 1295), + ('\u{510}', 1297), ('\u{512}', 1299), ('\u{514}', 1301), ('\u{516}', 1303), + ('\u{518}', 1305), ('\u{51a}', 1307), ('\u{51c}', 1309), ('\u{51e}', 1311), + ('\u{520}', 1313), ('\u{522}', 1315), ('\u{524}', 1317), ('\u{526}', 1319), + ('\u{528}', 1321), ('\u{52a}', 1323), ('\u{52c}', 1325), ('\u{52e}', 1327), + ('\u{531}', 1377), ('\u{532}', 1378), ('\u{533}', 1379), ('\u{534}', 1380), + ('\u{535}', 1381), ('\u{536}', 1382), ('\u{537}', 1383), ('\u{538}', 1384), + ('\u{539}', 1385), ('\u{53a}', 1386), ('\u{53b}', 1387), ('\u{53c}', 1388), + ('\u{53d}', 1389), ('\u{53e}', 1390), ('\u{53f}', 1391), ('\u{540}', 1392), + ('\u{541}', 1393), ('\u{542}', 1394), ('\u{543}', 1395), ('\u{544}', 1396), + ('\u{545}', 1397), ('\u{546}', 1398), ('\u{547}', 1399), ('\u{548}', 1400), + ('\u{549}', 1401), ('\u{54a}', 1402), ('\u{54b}', 1403), ('\u{54c}', 1404), + ('\u{54d}', 1405), ('\u{54e}', 1406), ('\u{54f}', 1407), ('\u{550}', 1408), + ('\u{551}', 1409), ('\u{552}', 1410), ('\u{553}', 1411), ('\u{554}', 1412), + ('\u{555}', 1413), ('\u{556}', 1414), ('\u{10a0}', 11520), ('\u{10a1}', 11521), + ('\u{10a2}', 11522), ('\u{10a3}', 11523), ('\u{10a4}', 11524), ('\u{10a5}', 11525), + ('\u{10a6}', 11526), ('\u{10a7}', 11527), ('\u{10a8}', 11528), ('\u{10a9}', 11529), + ('\u{10aa}', 11530), ('\u{10ab}', 11531), ('\u{10ac}', 11532), ('\u{10ad}', 11533), + ('\u{10ae}', 11534), ('\u{10af}', 11535), ('\u{10b0}', 11536), ('\u{10b1}', 11537), + ('\u{10b2}', 11538), ('\u{10b3}', 11539), ('\u{10b4}', 11540), ('\u{10b5}', 11541), + ('\u{10b6}', 11542), ('\u{10b7}', 11543), ('\u{10b8}', 11544), ('\u{10b9}', 11545), + ('\u{10ba}', 11546), ('\u{10bb}', 11547), ('\u{10bc}', 11548), ('\u{10bd}', 11549), + ('\u{10be}', 11550), ('\u{10bf}', 11551), ('\u{10c0}', 11552), ('\u{10c1}', 11553), + ('\u{10c2}', 11554), ('\u{10c3}', 11555), ('\u{10c4}', 11556), ('\u{10c5}', 11557), + ('\u{10c7}', 11559), ('\u{10cd}', 11565), ('\u{13a0}', 43888), ('\u{13a1}', 43889), + ('\u{13a2}', 43890), ('\u{13a3}', 43891), ('\u{13a4}', 43892), ('\u{13a5}', 43893), + ('\u{13a6}', 43894), ('\u{13a7}', 43895), ('\u{13a8}', 43896), ('\u{13a9}', 43897), + ('\u{13aa}', 43898), ('\u{13ab}', 43899), ('\u{13ac}', 43900), ('\u{13ad}', 43901), + ('\u{13ae}', 43902), ('\u{13af}', 43903), ('\u{13b0}', 43904), ('\u{13b1}', 43905), + ('\u{13b2}', 43906), ('\u{13b3}', 43907), ('\u{13b4}', 43908), ('\u{13b5}', 43909), + ('\u{13b6}', 43910), ('\u{13b7}', 43911), ('\u{13b8}', 43912), ('\u{13b9}', 43913), + ('\u{13ba}', 43914), ('\u{13bb}', 43915), ('\u{13bc}', 43916), ('\u{13bd}', 43917), + ('\u{13be}', 43918), ('\u{13bf}', 43919), ('\u{13c0}', 43920), ('\u{13c1}', 43921), + ('\u{13c2}', 43922), ('\u{13c3}', 43923), ('\u{13c4}', 43924), ('\u{13c5}', 43925), + ('\u{13c6}', 43926), ('\u{13c7}', 43927), ('\u{13c8}', 43928), ('\u{13c9}', 43929), + ('\u{13ca}', 43930), ('\u{13cb}', 43931), ('\u{13cc}', 43932), ('\u{13cd}', 43933), + ('\u{13ce}', 43934), ('\u{13cf}', 43935), ('\u{13d0}', 43936), ('\u{13d1}', 43937), + ('\u{13d2}', 43938), ('\u{13d3}', 43939), ('\u{13d4}', 43940), ('\u{13d5}', 43941), + ('\u{13d6}', 43942), ('\u{13d7}', 43943), ('\u{13d8}', 43944), ('\u{13d9}', 43945), + ('\u{13da}', 43946), ('\u{13db}', 43947), ('\u{13dc}', 43948), ('\u{13dd}', 43949), + ('\u{13de}', 43950), ('\u{13df}', 43951), ('\u{13e0}', 43952), ('\u{13e1}', 43953), + ('\u{13e2}', 43954), ('\u{13e3}', 43955), ('\u{13e4}', 43956), ('\u{13e5}', 43957), + ('\u{13e6}', 43958), ('\u{13e7}', 43959), ('\u{13e8}', 43960), ('\u{13e9}', 43961), + ('\u{13ea}', 43962), ('\u{13eb}', 43963), ('\u{13ec}', 43964), ('\u{13ed}', 43965), + ('\u{13ee}', 43966), ('\u{13ef}', 43967), ('\u{13f0}', 5112), ('\u{13f1}', 5113), + ('\u{13f2}', 5114), ('\u{13f3}', 5115), ('\u{13f4}', 5116), ('\u{13f5}', 5117), + ('\u{1c90}', 4304), ('\u{1c91}', 4305), ('\u{1c92}', 4306), ('\u{1c93}', 4307), + ('\u{1c94}', 4308), ('\u{1c95}', 4309), ('\u{1c96}', 4310), ('\u{1c97}', 4311), + ('\u{1c98}', 4312), ('\u{1c99}', 4313), ('\u{1c9a}', 4314), ('\u{1c9b}', 4315), + ('\u{1c9c}', 4316), ('\u{1c9d}', 4317), ('\u{1c9e}', 4318), ('\u{1c9f}', 4319), + ('\u{1ca0}', 4320), ('\u{1ca1}', 4321), ('\u{1ca2}', 4322), ('\u{1ca3}', 4323), + ('\u{1ca4}', 4324), ('\u{1ca5}', 4325), ('\u{1ca6}', 4326), ('\u{1ca7}', 4327), + ('\u{1ca8}', 4328), ('\u{1ca9}', 4329), ('\u{1caa}', 4330), ('\u{1cab}', 4331), + ('\u{1cac}', 4332), ('\u{1cad}', 4333), ('\u{1cae}', 4334), ('\u{1caf}', 4335), + ('\u{1cb0}', 4336), ('\u{1cb1}', 4337), ('\u{1cb2}', 4338), ('\u{1cb3}', 4339), + ('\u{1cb4}', 4340), ('\u{1cb5}', 4341), ('\u{1cb6}', 4342), ('\u{1cb7}', 4343), + ('\u{1cb8}', 4344), ('\u{1cb9}', 4345), ('\u{1cba}', 4346), ('\u{1cbd}', 4349), + ('\u{1cbe}', 4350), ('\u{1cbf}', 4351), ('\u{1e00}', 7681), ('\u{1e02}', 7683), + ('\u{1e04}', 7685), ('\u{1e06}', 7687), ('\u{1e08}', 7689), ('\u{1e0a}', 7691), + ('\u{1e0c}', 7693), ('\u{1e0e}', 7695), ('\u{1e10}', 7697), ('\u{1e12}', 7699), + ('\u{1e14}', 7701), ('\u{1e16}', 7703), ('\u{1e18}', 7705), ('\u{1e1a}', 7707), + ('\u{1e1c}', 7709), ('\u{1e1e}', 7711), ('\u{1e20}', 7713), ('\u{1e22}', 7715), + ('\u{1e24}', 7717), ('\u{1e26}', 7719), ('\u{1e28}', 7721), ('\u{1e2a}', 7723), + ('\u{1e2c}', 7725), ('\u{1e2e}', 7727), ('\u{1e30}', 7729), ('\u{1e32}', 7731), + ('\u{1e34}', 7733), ('\u{1e36}', 7735), ('\u{1e38}', 7737), ('\u{1e3a}', 7739), + ('\u{1e3c}', 7741), ('\u{1e3e}', 7743), ('\u{1e40}', 7745), ('\u{1e42}', 7747), + ('\u{1e44}', 7749), ('\u{1e46}', 7751), ('\u{1e48}', 7753), ('\u{1e4a}', 7755), + ('\u{1e4c}', 7757), ('\u{1e4e}', 7759), ('\u{1e50}', 7761), ('\u{1e52}', 7763), + ('\u{1e54}', 7765), ('\u{1e56}', 7767), ('\u{1e58}', 7769), ('\u{1e5a}', 7771), + ('\u{1e5c}', 7773), ('\u{1e5e}', 7775), ('\u{1e60}', 7777), ('\u{1e62}', 7779), + ('\u{1e64}', 7781), ('\u{1e66}', 7783), ('\u{1e68}', 7785), ('\u{1e6a}', 7787), + ('\u{1e6c}', 7789), ('\u{1e6e}', 7791), ('\u{1e70}', 7793), ('\u{1e72}', 7795), + ('\u{1e74}', 7797), ('\u{1e76}', 7799), ('\u{1e78}', 7801), ('\u{1e7a}', 7803), + ('\u{1e7c}', 7805), ('\u{1e7e}', 7807), ('\u{1e80}', 7809), ('\u{1e82}', 7811), + ('\u{1e84}', 7813), ('\u{1e86}', 7815), ('\u{1e88}', 7817), ('\u{1e8a}', 7819), + ('\u{1e8c}', 7821), ('\u{1e8e}', 7823), ('\u{1e90}', 7825), ('\u{1e92}', 7827), + ('\u{1e94}', 7829), ('\u{1e9e}', 223), ('\u{1ea0}', 7841), ('\u{1ea2}', 7843), + ('\u{1ea4}', 7845), ('\u{1ea6}', 7847), ('\u{1ea8}', 7849), ('\u{1eaa}', 7851), + ('\u{1eac}', 7853), ('\u{1eae}', 7855), ('\u{1eb0}', 7857), ('\u{1eb2}', 7859), + ('\u{1eb4}', 7861), ('\u{1eb6}', 7863), ('\u{1eb8}', 7865), ('\u{1eba}', 7867), + ('\u{1ebc}', 7869), ('\u{1ebe}', 7871), ('\u{1ec0}', 7873), ('\u{1ec2}', 7875), + ('\u{1ec4}', 7877), ('\u{1ec6}', 7879), ('\u{1ec8}', 7881), ('\u{1eca}', 7883), + ('\u{1ecc}', 7885), ('\u{1ece}', 7887), ('\u{1ed0}', 7889), ('\u{1ed2}', 7891), + ('\u{1ed4}', 7893), ('\u{1ed6}', 7895), ('\u{1ed8}', 7897), ('\u{1eda}', 7899), + ('\u{1edc}', 7901), ('\u{1ede}', 7903), ('\u{1ee0}', 7905), ('\u{1ee2}', 7907), + ('\u{1ee4}', 7909), ('\u{1ee6}', 7911), ('\u{1ee8}', 7913), ('\u{1eea}', 7915), + ('\u{1eec}', 7917), ('\u{1eee}', 7919), ('\u{1ef0}', 7921), ('\u{1ef2}', 7923), + ('\u{1ef4}', 7925), ('\u{1ef6}', 7927), ('\u{1ef8}', 7929), ('\u{1efa}', 7931), + ('\u{1efc}', 7933), ('\u{1efe}', 7935), ('\u{1f08}', 7936), ('\u{1f09}', 7937), + ('\u{1f0a}', 7938), ('\u{1f0b}', 7939), ('\u{1f0c}', 7940), ('\u{1f0d}', 7941), + ('\u{1f0e}', 7942), ('\u{1f0f}', 7943), ('\u{1f18}', 7952), ('\u{1f19}', 7953), + ('\u{1f1a}', 7954), ('\u{1f1b}', 7955), ('\u{1f1c}', 7956), ('\u{1f1d}', 7957), + ('\u{1f28}', 7968), ('\u{1f29}', 7969), ('\u{1f2a}', 7970), ('\u{1f2b}', 7971), + ('\u{1f2c}', 7972), ('\u{1f2d}', 7973), ('\u{1f2e}', 7974), ('\u{1f2f}', 7975), + ('\u{1f38}', 7984), ('\u{1f39}', 7985), ('\u{1f3a}', 7986), ('\u{1f3b}', 7987), + ('\u{1f3c}', 7988), ('\u{1f3d}', 7989), ('\u{1f3e}', 7990), ('\u{1f3f}', 7991), + ('\u{1f48}', 8000), ('\u{1f49}', 8001), ('\u{1f4a}', 8002), ('\u{1f4b}', 8003), + ('\u{1f4c}', 8004), ('\u{1f4d}', 8005), ('\u{1f59}', 8017), ('\u{1f5b}', 8019), + ('\u{1f5d}', 8021), ('\u{1f5f}', 8023), ('\u{1f68}', 8032), ('\u{1f69}', 8033), + ('\u{1f6a}', 8034), ('\u{1f6b}', 8035), ('\u{1f6c}', 8036), ('\u{1f6d}', 8037), + ('\u{1f6e}', 8038), ('\u{1f6f}', 8039), ('\u{1f88}', 8064), ('\u{1f89}', 8065), + ('\u{1f8a}', 8066), ('\u{1f8b}', 8067), ('\u{1f8c}', 8068), ('\u{1f8d}', 8069), + ('\u{1f8e}', 8070), ('\u{1f8f}', 8071), ('\u{1f98}', 8080), ('\u{1f99}', 8081), + ('\u{1f9a}', 8082), ('\u{1f9b}', 8083), ('\u{1f9c}', 8084), ('\u{1f9d}', 8085), + ('\u{1f9e}', 8086), ('\u{1f9f}', 8087), ('\u{1fa8}', 8096), ('\u{1fa9}', 8097), + ('\u{1faa}', 8098), ('\u{1fab}', 8099), ('\u{1fac}', 8100), ('\u{1fad}', 8101), + ('\u{1fae}', 8102), ('\u{1faf}', 8103), ('\u{1fb8}', 8112), ('\u{1fb9}', 8113), + ('\u{1fba}', 8048), ('\u{1fbb}', 8049), ('\u{1fbc}', 8115), ('\u{1fc8}', 8050), + ('\u{1fc9}', 8051), ('\u{1fca}', 8052), ('\u{1fcb}', 8053), ('\u{1fcc}', 8131), + ('\u{1fd8}', 8144), ('\u{1fd9}', 8145), ('\u{1fda}', 8054), ('\u{1fdb}', 8055), + ('\u{1fe8}', 8160), ('\u{1fe9}', 8161), ('\u{1fea}', 8058), ('\u{1feb}', 8059), + ('\u{1fec}', 8165), ('\u{1ff8}', 8056), ('\u{1ff9}', 8057), ('\u{1ffa}', 8060), + ('\u{1ffb}', 8061), ('\u{1ffc}', 8179), ('\u{2126}', 969), ('\u{212a}', 107), + ('\u{212b}', 229), ('\u{2132}', 8526), ('\u{2160}', 8560), ('\u{2161}', 8561), + ('\u{2162}', 8562), ('\u{2163}', 8563), ('\u{2164}', 8564), ('\u{2165}', 8565), + ('\u{2166}', 8566), ('\u{2167}', 8567), ('\u{2168}', 8568), ('\u{2169}', 8569), + ('\u{216a}', 8570), ('\u{216b}', 8571), ('\u{216c}', 8572), ('\u{216d}', 8573), + ('\u{216e}', 8574), ('\u{216f}', 8575), ('\u{2183}', 8580), ('\u{24b6}', 9424), + ('\u{24b7}', 9425), ('\u{24b8}', 9426), ('\u{24b9}', 9427), ('\u{24ba}', 9428), + ('\u{24bb}', 9429), ('\u{24bc}', 9430), ('\u{24bd}', 9431), ('\u{24be}', 9432), + ('\u{24bf}', 9433), ('\u{24c0}', 9434), ('\u{24c1}', 9435), ('\u{24c2}', 9436), + ('\u{24c3}', 9437), ('\u{24c4}', 9438), ('\u{24c5}', 9439), ('\u{24c6}', 9440), + ('\u{24c7}', 9441), ('\u{24c8}', 9442), ('\u{24c9}', 9443), ('\u{24ca}', 9444), + ('\u{24cb}', 9445), ('\u{24cc}', 9446), ('\u{24cd}', 9447), ('\u{24ce}', 9448), + ('\u{24cf}', 9449), ('\u{2c00}', 11312), ('\u{2c01}', 11313), ('\u{2c02}', 11314), + ('\u{2c03}', 11315), ('\u{2c04}', 11316), ('\u{2c05}', 11317), ('\u{2c06}', 11318), + ('\u{2c07}', 11319), ('\u{2c08}', 11320), ('\u{2c09}', 11321), ('\u{2c0a}', 11322), + ('\u{2c0b}', 11323), ('\u{2c0c}', 11324), ('\u{2c0d}', 11325), ('\u{2c0e}', 11326), + ('\u{2c0f}', 11327), ('\u{2c10}', 11328), ('\u{2c11}', 11329), ('\u{2c12}', 11330), + ('\u{2c13}', 11331), ('\u{2c14}', 11332), ('\u{2c15}', 11333), ('\u{2c16}', 11334), + ('\u{2c17}', 11335), ('\u{2c18}', 11336), ('\u{2c19}', 11337), ('\u{2c1a}', 11338), + ('\u{2c1b}', 11339), ('\u{2c1c}', 11340), ('\u{2c1d}', 11341), ('\u{2c1e}', 11342), + ('\u{2c1f}', 11343), ('\u{2c20}', 11344), ('\u{2c21}', 11345), ('\u{2c22}', 11346), + ('\u{2c23}', 11347), ('\u{2c24}', 11348), ('\u{2c25}', 11349), ('\u{2c26}', 11350), + ('\u{2c27}', 11351), ('\u{2c28}', 11352), ('\u{2c29}', 11353), ('\u{2c2a}', 11354), + ('\u{2c2b}', 11355), ('\u{2c2c}', 11356), ('\u{2c2d}', 11357), ('\u{2c2e}', 11358), + ('\u{2c2f}', 11359), ('\u{2c60}', 11361), ('\u{2c62}', 619), ('\u{2c63}', 7549), + ('\u{2c64}', 637), ('\u{2c67}', 11368), ('\u{2c69}', 11370), ('\u{2c6b}', 11372), + ('\u{2c6d}', 593), ('\u{2c6e}', 625), ('\u{2c6f}', 592), ('\u{2c70}', 594), + ('\u{2c72}', 11379), ('\u{2c75}', 11382), ('\u{2c7e}', 575), ('\u{2c7f}', 576), + ('\u{2c80}', 11393), ('\u{2c82}', 11395), ('\u{2c84}', 11397), ('\u{2c86}', 11399), + ('\u{2c88}', 11401), ('\u{2c8a}', 11403), ('\u{2c8c}', 11405), ('\u{2c8e}', 11407), + ('\u{2c90}', 11409), ('\u{2c92}', 11411), ('\u{2c94}', 11413), ('\u{2c96}', 11415), + ('\u{2c98}', 11417), ('\u{2c9a}', 11419), ('\u{2c9c}', 11421), ('\u{2c9e}', 11423), + ('\u{2ca0}', 11425), ('\u{2ca2}', 11427), ('\u{2ca4}', 11429), ('\u{2ca6}', 11431), + ('\u{2ca8}', 11433), ('\u{2caa}', 11435), ('\u{2cac}', 11437), ('\u{2cae}', 11439), + ('\u{2cb0}', 11441), ('\u{2cb2}', 11443), ('\u{2cb4}', 11445), ('\u{2cb6}', 11447), + ('\u{2cb8}', 11449), ('\u{2cba}', 11451), ('\u{2cbc}', 11453), ('\u{2cbe}', 11455), + ('\u{2cc0}', 11457), ('\u{2cc2}', 11459), ('\u{2cc4}', 11461), ('\u{2cc6}', 11463), + ('\u{2cc8}', 11465), ('\u{2cca}', 11467), ('\u{2ccc}', 11469), ('\u{2cce}', 11471), + ('\u{2cd0}', 11473), ('\u{2cd2}', 11475), ('\u{2cd4}', 11477), ('\u{2cd6}', 11479), + ('\u{2cd8}', 11481), ('\u{2cda}', 11483), ('\u{2cdc}', 11485), ('\u{2cde}', 11487), + ('\u{2ce0}', 11489), ('\u{2ce2}', 11491), ('\u{2ceb}', 11500), ('\u{2ced}', 11502), + ('\u{2cf2}', 11507), ('\u{a640}', 42561), ('\u{a642}', 42563), ('\u{a644}', 42565), + ('\u{a646}', 42567), ('\u{a648}', 42569), ('\u{a64a}', 42571), ('\u{a64c}', 42573), + ('\u{a64e}', 42575), ('\u{a650}', 42577), ('\u{a652}', 42579), ('\u{a654}', 42581), + ('\u{a656}', 42583), ('\u{a658}', 42585), ('\u{a65a}', 42587), ('\u{a65c}', 42589), + ('\u{a65e}', 42591), ('\u{a660}', 42593), ('\u{a662}', 42595), ('\u{a664}', 42597), + ('\u{a666}', 42599), ('\u{a668}', 42601), ('\u{a66a}', 42603), ('\u{a66c}', 42605), + ('\u{a680}', 42625), ('\u{a682}', 42627), ('\u{a684}', 42629), ('\u{a686}', 42631), + ('\u{a688}', 42633), ('\u{a68a}', 42635), ('\u{a68c}', 42637), ('\u{a68e}', 42639), + ('\u{a690}', 42641), ('\u{a692}', 42643), ('\u{a694}', 42645), ('\u{a696}', 42647), + ('\u{a698}', 42649), ('\u{a69a}', 42651), ('\u{a722}', 42787), ('\u{a724}', 42789), + ('\u{a726}', 42791), ('\u{a728}', 42793), ('\u{a72a}', 42795), ('\u{a72c}', 42797), + ('\u{a72e}', 42799), ('\u{a732}', 42803), ('\u{a734}', 42805), ('\u{a736}', 42807), + ('\u{a738}', 42809), ('\u{a73a}', 42811), ('\u{a73c}', 42813), ('\u{a73e}', 42815), + ('\u{a740}', 42817), ('\u{a742}', 42819), ('\u{a744}', 42821), ('\u{a746}', 42823), + ('\u{a748}', 42825), ('\u{a74a}', 42827), ('\u{a74c}', 42829), ('\u{a74e}', 42831), + ('\u{a750}', 42833), ('\u{a752}', 42835), ('\u{a754}', 42837), ('\u{a756}', 42839), + ('\u{a758}', 42841), ('\u{a75a}', 42843), ('\u{a75c}', 42845), ('\u{a75e}', 42847), + ('\u{a760}', 42849), ('\u{a762}', 42851), ('\u{a764}', 42853), ('\u{a766}', 42855), + ('\u{a768}', 42857), ('\u{a76a}', 42859), ('\u{a76c}', 42861), ('\u{a76e}', 42863), + ('\u{a779}', 42874), ('\u{a77b}', 42876), ('\u{a77d}', 7545), ('\u{a77e}', 42879), + ('\u{a780}', 42881), ('\u{a782}', 42883), ('\u{a784}', 42885), ('\u{a786}', 42887), + ('\u{a78b}', 42892), ('\u{a78d}', 613), ('\u{a790}', 42897), ('\u{a792}', 42899), + ('\u{a796}', 42903), ('\u{a798}', 42905), ('\u{a79a}', 42907), ('\u{a79c}', 42909), + ('\u{a79e}', 42911), ('\u{a7a0}', 42913), ('\u{a7a2}', 42915), ('\u{a7a4}', 42917), + ('\u{a7a6}', 42919), ('\u{a7a8}', 42921), ('\u{a7aa}', 614), ('\u{a7ab}', 604), + ('\u{a7ac}', 609), ('\u{a7ad}', 620), ('\u{a7ae}', 618), ('\u{a7b0}', 670), + ('\u{a7b1}', 647), ('\u{a7b2}', 669), ('\u{a7b3}', 43859), ('\u{a7b4}', 42933), + ('\u{a7b6}', 42935), ('\u{a7b8}', 42937), ('\u{a7ba}', 42939), ('\u{a7bc}', 42941), + ('\u{a7be}', 42943), ('\u{a7c0}', 42945), ('\u{a7c2}', 42947), ('\u{a7c4}', 42900), + ('\u{a7c5}', 642), ('\u{a7c6}', 7566), ('\u{a7c7}', 42952), ('\u{a7c9}', 42954), + ('\u{a7d0}', 42961), ('\u{a7d6}', 42967), ('\u{a7d8}', 42969), ('\u{a7f5}', 42998), + ('\u{ff21}', 65345), ('\u{ff22}', 65346), ('\u{ff23}', 65347), ('\u{ff24}', 65348), + ('\u{ff25}', 65349), ('\u{ff26}', 65350), ('\u{ff27}', 65351), ('\u{ff28}', 65352), + ('\u{ff29}', 65353), ('\u{ff2a}', 65354), ('\u{ff2b}', 65355), ('\u{ff2c}', 65356), + ('\u{ff2d}', 65357), ('\u{ff2e}', 65358), ('\u{ff2f}', 65359), ('\u{ff30}', 65360), + ('\u{ff31}', 65361), ('\u{ff32}', 65362), ('\u{ff33}', 65363), ('\u{ff34}', 65364), + ('\u{ff35}', 65365), ('\u{ff36}', 65366), ('\u{ff37}', 65367), ('\u{ff38}', 65368), + ('\u{ff39}', 65369), ('\u{ff3a}', 65370), ('\u{10400}', 66600), ('\u{10401}', 66601), + ('\u{10402}', 66602), ('\u{10403}', 66603), ('\u{10404}', 66604), ('\u{10405}', 66605), + ('\u{10406}', 66606), ('\u{10407}', 66607), ('\u{10408}', 66608), ('\u{10409}', 66609), + ('\u{1040a}', 66610), ('\u{1040b}', 66611), ('\u{1040c}', 66612), ('\u{1040d}', 66613), + ('\u{1040e}', 66614), ('\u{1040f}', 66615), ('\u{10410}', 66616), ('\u{10411}', 66617), + ('\u{10412}', 66618), ('\u{10413}', 66619), ('\u{10414}', 66620), ('\u{10415}', 66621), + ('\u{10416}', 66622), ('\u{10417}', 66623), ('\u{10418}', 66624), ('\u{10419}', 66625), + ('\u{1041a}', 66626), ('\u{1041b}', 66627), ('\u{1041c}', 66628), ('\u{1041d}', 66629), + ('\u{1041e}', 66630), ('\u{1041f}', 66631), ('\u{10420}', 66632), ('\u{10421}', 66633), + ('\u{10422}', 66634), ('\u{10423}', 66635), ('\u{10424}', 66636), ('\u{10425}', 66637), + ('\u{10426}', 66638), ('\u{10427}', 66639), ('\u{104b0}', 66776), ('\u{104b1}', 66777), + ('\u{104b2}', 66778), ('\u{104b3}', 66779), ('\u{104b4}', 66780), ('\u{104b5}', 66781), + ('\u{104b6}', 66782), ('\u{104b7}', 66783), ('\u{104b8}', 66784), ('\u{104b9}', 66785), + ('\u{104ba}', 66786), ('\u{104bb}', 66787), ('\u{104bc}', 66788), ('\u{104bd}', 66789), + ('\u{104be}', 66790), ('\u{104bf}', 66791), ('\u{104c0}', 66792), ('\u{104c1}', 66793), + ('\u{104c2}', 66794), ('\u{104c3}', 66795), ('\u{104c4}', 66796), ('\u{104c5}', 66797), + ('\u{104c6}', 66798), ('\u{104c7}', 66799), ('\u{104c8}', 66800), ('\u{104c9}', 66801), + ('\u{104ca}', 66802), ('\u{104cb}', 66803), ('\u{104cc}', 66804), ('\u{104cd}', 66805), + ('\u{104ce}', 66806), ('\u{104cf}', 66807), ('\u{104d0}', 66808), ('\u{104d1}', 66809), + ('\u{104d2}', 66810), ('\u{104d3}', 66811), ('\u{10570}', 66967), ('\u{10571}', 66968), + ('\u{10572}', 66969), ('\u{10573}', 66970), ('\u{10574}', 66971), ('\u{10575}', 66972), + ('\u{10576}', 66973), ('\u{10577}', 66974), ('\u{10578}', 66975), ('\u{10579}', 66976), + ('\u{1057a}', 66977), ('\u{1057c}', 66979), ('\u{1057d}', 66980), ('\u{1057e}', 66981), + ('\u{1057f}', 66982), ('\u{10580}', 66983), ('\u{10581}', 66984), ('\u{10582}', 66985), + ('\u{10583}', 66986), ('\u{10584}', 66987), ('\u{10585}', 66988), ('\u{10586}', 66989), + ('\u{10587}', 66990), ('\u{10588}', 66991), ('\u{10589}', 66992), ('\u{1058a}', 66993), + ('\u{1058c}', 66995), ('\u{1058d}', 66996), ('\u{1058e}', 66997), ('\u{1058f}', 66998), + ('\u{10590}', 66999), ('\u{10591}', 67000), ('\u{10592}', 67001), ('\u{10594}', 67003), + ('\u{10595}', 67004), ('\u{10c80}', 68800), ('\u{10c81}', 68801), ('\u{10c82}', 68802), + ('\u{10c83}', 68803), ('\u{10c84}', 68804), ('\u{10c85}', 68805), ('\u{10c86}', 68806), + ('\u{10c87}', 68807), ('\u{10c88}', 68808), ('\u{10c89}', 68809), ('\u{10c8a}', 68810), + ('\u{10c8b}', 68811), ('\u{10c8c}', 68812), ('\u{10c8d}', 68813), ('\u{10c8e}', 68814), + ('\u{10c8f}', 68815), ('\u{10c90}', 68816), ('\u{10c91}', 68817), ('\u{10c92}', 68818), + ('\u{10c93}', 68819), ('\u{10c94}', 68820), ('\u{10c95}', 68821), ('\u{10c96}', 68822), + ('\u{10c97}', 68823), ('\u{10c98}', 68824), ('\u{10c99}', 68825), ('\u{10c9a}', 68826), + ('\u{10c9b}', 68827), ('\u{10c9c}', 68828), ('\u{10c9d}', 68829), ('\u{10c9e}', 68830), + ('\u{10c9f}', 68831), ('\u{10ca0}', 68832), ('\u{10ca1}', 68833), ('\u{10ca2}', 68834), + ('\u{10ca3}', 68835), ('\u{10ca4}', 68836), ('\u{10ca5}', 68837), ('\u{10ca6}', 68838), + ('\u{10ca7}', 68839), ('\u{10ca8}', 68840), ('\u{10ca9}', 68841), ('\u{10caa}', 68842), + ('\u{10cab}', 68843), ('\u{10cac}', 68844), ('\u{10cad}', 68845), ('\u{10cae}', 68846), + ('\u{10caf}', 68847), ('\u{10cb0}', 68848), ('\u{10cb1}', 68849), ('\u{10cb2}', 68850), + ('\u{118a0}', 71872), ('\u{118a1}', 71873), ('\u{118a2}', 71874), ('\u{118a3}', 71875), + ('\u{118a4}', 71876), ('\u{118a5}', 71877), ('\u{118a6}', 71878), ('\u{118a7}', 71879), + ('\u{118a8}', 71880), ('\u{118a9}', 71881), ('\u{118aa}', 71882), ('\u{118ab}', 71883), + ('\u{118ac}', 71884), ('\u{118ad}', 71885), ('\u{118ae}', 71886), ('\u{118af}', 71887), + ('\u{118b0}', 71888), ('\u{118b1}', 71889), ('\u{118b2}', 71890), ('\u{118b3}', 71891), + ('\u{118b4}', 71892), ('\u{118b5}', 71893), ('\u{118b6}', 71894), ('\u{118b7}', 71895), + ('\u{118b8}', 71896), ('\u{118b9}', 71897), ('\u{118ba}', 71898), ('\u{118bb}', 71899), + ('\u{118bc}', 71900), ('\u{118bd}', 71901), ('\u{118be}', 71902), ('\u{118bf}', 71903), + ('\u{16e40}', 93792), ('\u{16e41}', 93793), ('\u{16e42}', 93794), ('\u{16e43}', 93795), + ('\u{16e44}', 93796), ('\u{16e45}', 93797), ('\u{16e46}', 93798), ('\u{16e47}', 93799), + ('\u{16e48}', 93800), ('\u{16e49}', 93801), ('\u{16e4a}', 93802), ('\u{16e4b}', 93803), + ('\u{16e4c}', 93804), ('\u{16e4d}', 93805), ('\u{16e4e}', 93806), ('\u{16e4f}', 93807), + ('\u{16e50}', 93808), ('\u{16e51}', 93809), ('\u{16e52}', 93810), ('\u{16e53}', 93811), + ('\u{16e54}', 93812), ('\u{16e55}', 93813), ('\u{16e56}', 93814), ('\u{16e57}', 93815), + ('\u{16e58}', 93816), ('\u{16e59}', 93817), ('\u{16e5a}', 93818), ('\u{16e5b}', 93819), + ('\u{16e5c}', 93820), ('\u{16e5d}', 93821), ('\u{16e5e}', 93822), ('\u{16e5f}', 93823), + ('\u{1e900}', 125218), ('\u{1e901}', 125219), ('\u{1e902}', 125220), ('\u{1e903}', 125221), + ('\u{1e904}', 125222), ('\u{1e905}', 125223), ('\u{1e906}', 125224), ('\u{1e907}', 125225), + ('\u{1e908}', 125226), ('\u{1e909}', 125227), ('\u{1e90a}', 125228), ('\u{1e90b}', 125229), + ('\u{1e90c}', 125230), ('\u{1e90d}', 125231), ('\u{1e90e}', 125232), ('\u{1e90f}', 125233), + ('\u{1e910}', 125234), ('\u{1e911}', 125235), ('\u{1e912}', 125236), ('\u{1e913}', 125237), + ('\u{1e914}', 125238), ('\u{1e915}', 125239), ('\u{1e916}', 125240), ('\u{1e917}', 125241), + ('\u{1e918}', 125242), ('\u{1e919}', 125243), ('\u{1e91a}', 125244), ('\u{1e91b}', 125245), + ('\u{1e91c}', 125246), ('\u{1e91d}', 125247), ('\u{1e91e}', 125248), ('\u{1e91f}', 125249), + ('\u{1e920}', 125250), ('\u{1e921}', 125251), + ]; + + static LOWERCASE_TABLE_MULTI: &[[char; 3]] = &[ + ['i', '\u{307}', '\u{0}'], + ]; + + static UPPERCASE_TABLE: &[(char, u32)] = &[ + ('\u{b5}', 924), ('\u{df}', 4194304), ('\u{e0}', 192), ('\u{e1}', 193), ('\u{e2}', 194), + ('\u{e3}', 195), ('\u{e4}', 196), ('\u{e5}', 197), ('\u{e6}', 198), ('\u{e7}', 199), + ('\u{e8}', 200), ('\u{e9}', 201), ('\u{ea}', 202), ('\u{eb}', 203), ('\u{ec}', 204), + ('\u{ed}', 205), ('\u{ee}', 206), ('\u{ef}', 207), ('\u{f0}', 208), ('\u{f1}', 209), + ('\u{f2}', 210), ('\u{f3}', 211), ('\u{f4}', 212), ('\u{f5}', 213), ('\u{f6}', 214), + ('\u{f8}', 216), ('\u{f9}', 217), ('\u{fa}', 218), ('\u{fb}', 219), ('\u{fc}', 220), + ('\u{fd}', 221), ('\u{fe}', 222), ('\u{ff}', 376), ('\u{101}', 256), ('\u{103}', 258), + ('\u{105}', 260), ('\u{107}', 262), ('\u{109}', 264), ('\u{10b}', 266), ('\u{10d}', 268), + ('\u{10f}', 270), ('\u{111}', 272), ('\u{113}', 274), ('\u{115}', 276), ('\u{117}', 278), + ('\u{119}', 280), ('\u{11b}', 282), ('\u{11d}', 284), ('\u{11f}', 286), ('\u{121}', 288), + ('\u{123}', 290), ('\u{125}', 292), ('\u{127}', 294), ('\u{129}', 296), ('\u{12b}', 298), + ('\u{12d}', 300), ('\u{12f}', 302), ('\u{131}', 73), ('\u{133}', 306), ('\u{135}', 308), + ('\u{137}', 310), ('\u{13a}', 313), ('\u{13c}', 315), ('\u{13e}', 317), ('\u{140}', 319), + ('\u{142}', 321), ('\u{144}', 323), ('\u{146}', 325), ('\u{148}', 327), + ('\u{149}', 4194305), ('\u{14b}', 330), ('\u{14d}', 332), ('\u{14f}', 334), + ('\u{151}', 336), ('\u{153}', 338), ('\u{155}', 340), ('\u{157}', 342), ('\u{159}', 344), + ('\u{15b}', 346), ('\u{15d}', 348), ('\u{15f}', 350), ('\u{161}', 352), ('\u{163}', 354), + ('\u{165}', 356), ('\u{167}', 358), ('\u{169}', 360), ('\u{16b}', 362), ('\u{16d}', 364), + ('\u{16f}', 366), ('\u{171}', 368), ('\u{173}', 370), ('\u{175}', 372), ('\u{177}', 374), + ('\u{17a}', 377), ('\u{17c}', 379), ('\u{17e}', 381), ('\u{17f}', 83), ('\u{180}', 579), + ('\u{183}', 386), ('\u{185}', 388), ('\u{188}', 391), ('\u{18c}', 395), ('\u{192}', 401), + ('\u{195}', 502), ('\u{199}', 408), ('\u{19a}', 573), ('\u{19e}', 544), ('\u{1a1}', 416), + ('\u{1a3}', 418), ('\u{1a5}', 420), ('\u{1a8}', 423), ('\u{1ad}', 428), ('\u{1b0}', 431), + ('\u{1b4}', 435), ('\u{1b6}', 437), ('\u{1b9}', 440), ('\u{1bd}', 444), ('\u{1bf}', 503), + ('\u{1c5}', 452), ('\u{1c6}', 452), ('\u{1c8}', 455), ('\u{1c9}', 455), ('\u{1cb}', 458), + ('\u{1cc}', 458), ('\u{1ce}', 461), ('\u{1d0}', 463), ('\u{1d2}', 465), ('\u{1d4}', 467), + ('\u{1d6}', 469), ('\u{1d8}', 471), ('\u{1da}', 473), ('\u{1dc}', 475), ('\u{1dd}', 398), + ('\u{1df}', 478), ('\u{1e1}', 480), ('\u{1e3}', 482), ('\u{1e5}', 484), ('\u{1e7}', 486), + ('\u{1e9}', 488), ('\u{1eb}', 490), ('\u{1ed}', 492), ('\u{1ef}', 494), + ('\u{1f0}', 4194306), ('\u{1f2}', 497), ('\u{1f3}', 497), ('\u{1f5}', 500), + ('\u{1f9}', 504), ('\u{1fb}', 506), ('\u{1fd}', 508), ('\u{1ff}', 510), ('\u{201}', 512), + ('\u{203}', 514), ('\u{205}', 516), ('\u{207}', 518), ('\u{209}', 520), ('\u{20b}', 522), + ('\u{20d}', 524), ('\u{20f}', 526), ('\u{211}', 528), ('\u{213}', 530), ('\u{215}', 532), + ('\u{217}', 534), ('\u{219}', 536), ('\u{21b}', 538), ('\u{21d}', 540), ('\u{21f}', 542), + ('\u{223}', 546), ('\u{225}', 548), ('\u{227}', 550), ('\u{229}', 552), ('\u{22b}', 554), + ('\u{22d}', 556), ('\u{22f}', 558), ('\u{231}', 560), ('\u{233}', 562), ('\u{23c}', 571), + ('\u{23f}', 11390), ('\u{240}', 11391), ('\u{242}', 577), ('\u{247}', 582), + ('\u{249}', 584), ('\u{24b}', 586), ('\u{24d}', 588), ('\u{24f}', 590), ('\u{250}', 11375), + ('\u{251}', 11373), ('\u{252}', 11376), ('\u{253}', 385), ('\u{254}', 390), + ('\u{256}', 393), ('\u{257}', 394), ('\u{259}', 399), ('\u{25b}', 400), ('\u{25c}', 42923), + ('\u{260}', 403), ('\u{261}', 42924), ('\u{263}', 404), ('\u{265}', 42893), + ('\u{266}', 42922), ('\u{268}', 407), ('\u{269}', 406), ('\u{26a}', 42926), + ('\u{26b}', 11362), ('\u{26c}', 42925), ('\u{26f}', 412), ('\u{271}', 11374), + ('\u{272}', 413), ('\u{275}', 415), ('\u{27d}', 11364), ('\u{280}', 422), + ('\u{282}', 42949), ('\u{283}', 425), ('\u{287}', 42929), ('\u{288}', 430), + ('\u{289}', 580), ('\u{28a}', 433), ('\u{28b}', 434), ('\u{28c}', 581), ('\u{292}', 439), + ('\u{29d}', 42930), ('\u{29e}', 42928), ('\u{345}', 921), ('\u{371}', 880), + ('\u{373}', 882), ('\u{377}', 886), ('\u{37b}', 1021), ('\u{37c}', 1022), ('\u{37d}', 1023), + ('\u{390}', 4194307), ('\u{3ac}', 902), ('\u{3ad}', 904), ('\u{3ae}', 905), + ('\u{3af}', 906), ('\u{3b0}', 4194308), ('\u{3b1}', 913), ('\u{3b2}', 914), + ('\u{3b3}', 915), ('\u{3b4}', 916), ('\u{3b5}', 917), ('\u{3b6}', 918), ('\u{3b7}', 919), + ('\u{3b8}', 920), ('\u{3b9}', 921), ('\u{3ba}', 922), ('\u{3bb}', 923), ('\u{3bc}', 924), + ('\u{3bd}', 925), ('\u{3be}', 926), ('\u{3bf}', 927), ('\u{3c0}', 928), ('\u{3c1}', 929), + ('\u{3c2}', 931), ('\u{3c3}', 931), ('\u{3c4}', 932), ('\u{3c5}', 933), ('\u{3c6}', 934), + ('\u{3c7}', 935), ('\u{3c8}', 936), ('\u{3c9}', 937), ('\u{3ca}', 938), ('\u{3cb}', 939), + ('\u{3cc}', 908), ('\u{3cd}', 910), ('\u{3ce}', 911), ('\u{3d0}', 914), ('\u{3d1}', 920), + ('\u{3d5}', 934), ('\u{3d6}', 928), ('\u{3d7}', 975), ('\u{3d9}', 984), ('\u{3db}', 986), + ('\u{3dd}', 988), ('\u{3df}', 990), ('\u{3e1}', 992), ('\u{3e3}', 994), ('\u{3e5}', 996), + ('\u{3e7}', 998), ('\u{3e9}', 1000), ('\u{3eb}', 1002), ('\u{3ed}', 1004), + ('\u{3ef}', 1006), ('\u{3f0}', 922), ('\u{3f1}', 929), ('\u{3f2}', 1017), ('\u{3f3}', 895), + ('\u{3f5}', 917), ('\u{3f8}', 1015), ('\u{3fb}', 1018), ('\u{430}', 1040), + ('\u{431}', 1041), ('\u{432}', 1042), ('\u{433}', 1043), ('\u{434}', 1044), + ('\u{435}', 1045), ('\u{436}', 1046), ('\u{437}', 1047), ('\u{438}', 1048), + ('\u{439}', 1049), ('\u{43a}', 1050), ('\u{43b}', 1051), ('\u{43c}', 1052), + ('\u{43d}', 1053), ('\u{43e}', 1054), ('\u{43f}', 1055), ('\u{440}', 1056), + ('\u{441}', 1057), ('\u{442}', 1058), ('\u{443}', 1059), ('\u{444}', 1060), + ('\u{445}', 1061), ('\u{446}', 1062), ('\u{447}', 1063), ('\u{448}', 1064), + ('\u{449}', 1065), ('\u{44a}', 1066), ('\u{44b}', 1067), ('\u{44c}', 1068), + ('\u{44d}', 1069), ('\u{44e}', 1070), ('\u{44f}', 1071), ('\u{450}', 1024), + ('\u{451}', 1025), ('\u{452}', 1026), ('\u{453}', 1027), ('\u{454}', 1028), + ('\u{455}', 1029), ('\u{456}', 1030), ('\u{457}', 1031), ('\u{458}', 1032), + ('\u{459}', 1033), ('\u{45a}', 1034), ('\u{45b}', 1035), ('\u{45c}', 1036), + ('\u{45d}', 1037), ('\u{45e}', 1038), ('\u{45f}', 1039), ('\u{461}', 1120), + ('\u{463}', 1122), ('\u{465}', 1124), ('\u{467}', 1126), ('\u{469}', 1128), + ('\u{46b}', 1130), ('\u{46d}', 1132), ('\u{46f}', 1134), ('\u{471}', 1136), + ('\u{473}', 1138), ('\u{475}', 1140), ('\u{477}', 1142), ('\u{479}', 1144), + ('\u{47b}', 1146), ('\u{47d}', 1148), ('\u{47f}', 1150), ('\u{481}', 1152), + ('\u{48b}', 1162), ('\u{48d}', 1164), ('\u{48f}', 1166), ('\u{491}', 1168), + ('\u{493}', 1170), ('\u{495}', 1172), ('\u{497}', 1174), ('\u{499}', 1176), + ('\u{49b}', 1178), ('\u{49d}', 1180), ('\u{49f}', 1182), ('\u{4a1}', 1184), + ('\u{4a3}', 1186), ('\u{4a5}', 1188), ('\u{4a7}', 1190), ('\u{4a9}', 1192), + ('\u{4ab}', 1194), ('\u{4ad}', 1196), ('\u{4af}', 1198), ('\u{4b1}', 1200), + ('\u{4b3}', 1202), ('\u{4b5}', 1204), ('\u{4b7}', 1206), ('\u{4b9}', 1208), + ('\u{4bb}', 1210), ('\u{4bd}', 1212), ('\u{4bf}', 1214), ('\u{4c2}', 1217), + ('\u{4c4}', 1219), ('\u{4c6}', 1221), ('\u{4c8}', 1223), ('\u{4ca}', 1225), + ('\u{4cc}', 1227), ('\u{4ce}', 1229), ('\u{4cf}', 1216), ('\u{4d1}', 1232), + ('\u{4d3}', 1234), ('\u{4d5}', 1236), ('\u{4d7}', 1238), ('\u{4d9}', 1240), + ('\u{4db}', 1242), ('\u{4dd}', 1244), ('\u{4df}', 1246), ('\u{4e1}', 1248), + ('\u{4e3}', 1250), ('\u{4e5}', 1252), ('\u{4e7}', 1254), ('\u{4e9}', 1256), + ('\u{4eb}', 1258), ('\u{4ed}', 1260), ('\u{4ef}', 1262), ('\u{4f1}', 1264), + ('\u{4f3}', 1266), ('\u{4f5}', 1268), ('\u{4f7}', 1270), ('\u{4f9}', 1272), + ('\u{4fb}', 1274), ('\u{4fd}', 1276), ('\u{4ff}', 1278), ('\u{501}', 1280), + ('\u{503}', 1282), ('\u{505}', 1284), ('\u{507}', 1286), ('\u{509}', 1288), + ('\u{50b}', 1290), ('\u{50d}', 1292), ('\u{50f}', 1294), ('\u{511}', 1296), + ('\u{513}', 1298), ('\u{515}', 1300), ('\u{517}', 1302), ('\u{519}', 1304), + ('\u{51b}', 1306), ('\u{51d}', 1308), ('\u{51f}', 1310), ('\u{521}', 1312), + ('\u{523}', 1314), ('\u{525}', 1316), ('\u{527}', 1318), ('\u{529}', 1320), + ('\u{52b}', 1322), ('\u{52d}', 1324), ('\u{52f}', 1326), ('\u{561}', 1329), + ('\u{562}', 1330), ('\u{563}', 1331), ('\u{564}', 1332), ('\u{565}', 1333), + ('\u{566}', 1334), ('\u{567}', 1335), ('\u{568}', 1336), ('\u{569}', 1337), + ('\u{56a}', 1338), ('\u{56b}', 1339), ('\u{56c}', 1340), ('\u{56d}', 1341), + ('\u{56e}', 1342), ('\u{56f}', 1343), ('\u{570}', 1344), ('\u{571}', 1345), + ('\u{572}', 1346), ('\u{573}', 1347), ('\u{574}', 1348), ('\u{575}', 1349), + ('\u{576}', 1350), ('\u{577}', 1351), ('\u{578}', 1352), ('\u{579}', 1353), + ('\u{57a}', 1354), ('\u{57b}', 1355), ('\u{57c}', 1356), ('\u{57d}', 1357), + ('\u{57e}', 1358), ('\u{57f}', 1359), ('\u{580}', 1360), ('\u{581}', 1361), + ('\u{582}', 1362), ('\u{583}', 1363), ('\u{584}', 1364), ('\u{585}', 1365), + ('\u{586}', 1366), ('\u{587}', 4194309), ('\u{10d0}', 7312), ('\u{10d1}', 7313), + ('\u{10d2}', 7314), ('\u{10d3}', 7315), ('\u{10d4}', 7316), ('\u{10d5}', 7317), + ('\u{10d6}', 7318), ('\u{10d7}', 7319), ('\u{10d8}', 7320), ('\u{10d9}', 7321), + ('\u{10da}', 7322), ('\u{10db}', 7323), ('\u{10dc}', 7324), ('\u{10dd}', 7325), + ('\u{10de}', 7326), ('\u{10df}', 7327), ('\u{10e0}', 7328), ('\u{10e1}', 7329), + ('\u{10e2}', 7330), ('\u{10e3}', 7331), ('\u{10e4}', 7332), ('\u{10e5}', 7333), + ('\u{10e6}', 7334), ('\u{10e7}', 7335), ('\u{10e8}', 7336), ('\u{10e9}', 7337), + ('\u{10ea}', 7338), ('\u{10eb}', 7339), ('\u{10ec}', 7340), ('\u{10ed}', 7341), + ('\u{10ee}', 7342), ('\u{10ef}', 7343), ('\u{10f0}', 7344), ('\u{10f1}', 7345), + ('\u{10f2}', 7346), ('\u{10f3}', 7347), ('\u{10f4}', 7348), ('\u{10f5}', 7349), + ('\u{10f6}', 7350), ('\u{10f7}', 7351), ('\u{10f8}', 7352), ('\u{10f9}', 7353), + ('\u{10fa}', 7354), ('\u{10fd}', 7357), ('\u{10fe}', 7358), ('\u{10ff}', 7359), + ('\u{13f8}', 5104), ('\u{13f9}', 5105), ('\u{13fa}', 5106), ('\u{13fb}', 5107), + ('\u{13fc}', 5108), ('\u{13fd}', 5109), ('\u{1c80}', 1042), ('\u{1c81}', 1044), + ('\u{1c82}', 1054), ('\u{1c83}', 1057), ('\u{1c84}', 1058), ('\u{1c85}', 1058), + ('\u{1c86}', 1066), ('\u{1c87}', 1122), ('\u{1c88}', 42570), ('\u{1d79}', 42877), + ('\u{1d7d}', 11363), ('\u{1d8e}', 42950), ('\u{1e01}', 7680), ('\u{1e03}', 7682), + ('\u{1e05}', 7684), ('\u{1e07}', 7686), ('\u{1e09}', 7688), ('\u{1e0b}', 7690), + ('\u{1e0d}', 7692), ('\u{1e0f}', 7694), ('\u{1e11}', 7696), ('\u{1e13}', 7698), + ('\u{1e15}', 7700), ('\u{1e17}', 7702), ('\u{1e19}', 7704), ('\u{1e1b}', 7706), + ('\u{1e1d}', 7708), ('\u{1e1f}', 7710), ('\u{1e21}', 7712), ('\u{1e23}', 7714), + ('\u{1e25}', 7716), ('\u{1e27}', 7718), ('\u{1e29}', 7720), ('\u{1e2b}', 7722), + ('\u{1e2d}', 7724), ('\u{1e2f}', 7726), ('\u{1e31}', 7728), ('\u{1e33}', 7730), + ('\u{1e35}', 7732), ('\u{1e37}', 7734), ('\u{1e39}', 7736), ('\u{1e3b}', 7738), + ('\u{1e3d}', 7740), ('\u{1e3f}', 7742), ('\u{1e41}', 7744), ('\u{1e43}', 7746), + ('\u{1e45}', 7748), ('\u{1e47}', 7750), ('\u{1e49}', 7752), ('\u{1e4b}', 7754), + ('\u{1e4d}', 7756), ('\u{1e4f}', 7758), ('\u{1e51}', 7760), ('\u{1e53}', 7762), + ('\u{1e55}', 7764), ('\u{1e57}', 7766), ('\u{1e59}', 7768), ('\u{1e5b}', 7770), + ('\u{1e5d}', 7772), ('\u{1e5f}', 7774), ('\u{1e61}', 7776), ('\u{1e63}', 7778), + ('\u{1e65}', 7780), ('\u{1e67}', 7782), ('\u{1e69}', 7784), ('\u{1e6b}', 7786), + ('\u{1e6d}', 7788), ('\u{1e6f}', 7790), ('\u{1e71}', 7792), ('\u{1e73}', 7794), + ('\u{1e75}', 7796), ('\u{1e77}', 7798), ('\u{1e79}', 7800), ('\u{1e7b}', 7802), + ('\u{1e7d}', 7804), ('\u{1e7f}', 7806), ('\u{1e81}', 7808), ('\u{1e83}', 7810), + ('\u{1e85}', 7812), ('\u{1e87}', 7814), ('\u{1e89}', 7816), ('\u{1e8b}', 7818), + ('\u{1e8d}', 7820), ('\u{1e8f}', 7822), ('\u{1e91}', 7824), ('\u{1e93}', 7826), + ('\u{1e95}', 7828), ('\u{1e96}', 4194310), ('\u{1e97}', 4194311), ('\u{1e98}', 4194312), + ('\u{1e99}', 4194313), ('\u{1e9a}', 4194314), ('\u{1e9b}', 7776), ('\u{1ea1}', 7840), + ('\u{1ea3}', 7842), ('\u{1ea5}', 7844), ('\u{1ea7}', 7846), ('\u{1ea9}', 7848), + ('\u{1eab}', 7850), ('\u{1ead}', 7852), ('\u{1eaf}', 7854), ('\u{1eb1}', 7856), + ('\u{1eb3}', 7858), ('\u{1eb5}', 7860), ('\u{1eb7}', 7862), ('\u{1eb9}', 7864), + ('\u{1ebb}', 7866), ('\u{1ebd}', 7868), ('\u{1ebf}', 7870), ('\u{1ec1}', 7872), + ('\u{1ec3}', 7874), ('\u{1ec5}', 7876), ('\u{1ec7}', 7878), ('\u{1ec9}', 7880), + ('\u{1ecb}', 7882), ('\u{1ecd}', 7884), ('\u{1ecf}', 7886), ('\u{1ed1}', 7888), + ('\u{1ed3}', 7890), ('\u{1ed5}', 7892), ('\u{1ed7}', 7894), ('\u{1ed9}', 7896), + ('\u{1edb}', 7898), ('\u{1edd}', 7900), ('\u{1edf}', 7902), ('\u{1ee1}', 7904), + ('\u{1ee3}', 7906), ('\u{1ee5}', 7908), ('\u{1ee7}', 7910), ('\u{1ee9}', 7912), + ('\u{1eeb}', 7914), ('\u{1eed}', 7916), ('\u{1eef}', 7918), ('\u{1ef1}', 7920), + ('\u{1ef3}', 7922), ('\u{1ef5}', 7924), ('\u{1ef7}', 7926), ('\u{1ef9}', 7928), + ('\u{1efb}', 7930), ('\u{1efd}', 7932), ('\u{1eff}', 7934), ('\u{1f00}', 7944), + ('\u{1f01}', 7945), ('\u{1f02}', 7946), ('\u{1f03}', 7947), ('\u{1f04}', 7948), + ('\u{1f05}', 7949), ('\u{1f06}', 7950), ('\u{1f07}', 7951), ('\u{1f10}', 7960), + ('\u{1f11}', 7961), ('\u{1f12}', 7962), ('\u{1f13}', 7963), ('\u{1f14}', 7964), + ('\u{1f15}', 7965), ('\u{1f20}', 7976), ('\u{1f21}', 7977), ('\u{1f22}', 7978), + ('\u{1f23}', 7979), ('\u{1f24}', 7980), ('\u{1f25}', 7981), ('\u{1f26}', 7982), + ('\u{1f27}', 7983), ('\u{1f30}', 7992), ('\u{1f31}', 7993), ('\u{1f32}', 7994), + ('\u{1f33}', 7995), ('\u{1f34}', 7996), ('\u{1f35}', 7997), ('\u{1f36}', 7998), + ('\u{1f37}', 7999), ('\u{1f40}', 8008), ('\u{1f41}', 8009), ('\u{1f42}', 8010), + ('\u{1f43}', 8011), ('\u{1f44}', 8012), ('\u{1f45}', 8013), ('\u{1f50}', 4194315), + ('\u{1f51}', 8025), ('\u{1f52}', 4194316), ('\u{1f53}', 8027), ('\u{1f54}', 4194317), + ('\u{1f55}', 8029), ('\u{1f56}', 4194318), ('\u{1f57}', 8031), ('\u{1f60}', 8040), + ('\u{1f61}', 8041), ('\u{1f62}', 8042), ('\u{1f63}', 8043), ('\u{1f64}', 8044), + ('\u{1f65}', 8045), ('\u{1f66}', 8046), ('\u{1f67}', 8047), ('\u{1f70}', 8122), + ('\u{1f71}', 8123), ('\u{1f72}', 8136), ('\u{1f73}', 8137), ('\u{1f74}', 8138), + ('\u{1f75}', 8139), ('\u{1f76}', 8154), ('\u{1f77}', 8155), ('\u{1f78}', 8184), + ('\u{1f79}', 8185), ('\u{1f7a}', 8170), ('\u{1f7b}', 8171), ('\u{1f7c}', 8186), + ('\u{1f7d}', 8187), ('\u{1f80}', 4194319), ('\u{1f81}', 4194320), ('\u{1f82}', 4194321), + ('\u{1f83}', 4194322), ('\u{1f84}', 4194323), ('\u{1f85}', 4194324), ('\u{1f86}', 4194325), + ('\u{1f87}', 4194326), ('\u{1f88}', 4194327), ('\u{1f89}', 4194328), ('\u{1f8a}', 4194329), + ('\u{1f8b}', 4194330), ('\u{1f8c}', 4194331), ('\u{1f8d}', 4194332), ('\u{1f8e}', 4194333), + ('\u{1f8f}', 4194334), ('\u{1f90}', 4194335), ('\u{1f91}', 4194336), ('\u{1f92}', 4194337), + ('\u{1f93}', 4194338), ('\u{1f94}', 4194339), ('\u{1f95}', 4194340), ('\u{1f96}', 4194341), + ('\u{1f97}', 4194342), ('\u{1f98}', 4194343), ('\u{1f99}', 4194344), ('\u{1f9a}', 4194345), + ('\u{1f9b}', 4194346), ('\u{1f9c}', 4194347), ('\u{1f9d}', 4194348), ('\u{1f9e}', 4194349), + ('\u{1f9f}', 4194350), ('\u{1fa0}', 4194351), ('\u{1fa1}', 4194352), ('\u{1fa2}', 4194353), + ('\u{1fa3}', 4194354), ('\u{1fa4}', 4194355), ('\u{1fa5}', 4194356), ('\u{1fa6}', 4194357), + ('\u{1fa7}', 4194358), ('\u{1fa8}', 4194359), ('\u{1fa9}', 4194360), ('\u{1faa}', 4194361), + ('\u{1fab}', 4194362), ('\u{1fac}', 4194363), ('\u{1fad}', 4194364), ('\u{1fae}', 4194365), + ('\u{1faf}', 4194366), ('\u{1fb0}', 8120), ('\u{1fb1}', 8121), ('\u{1fb2}', 4194367), + ('\u{1fb3}', 4194368), ('\u{1fb4}', 4194369), ('\u{1fb6}', 4194370), ('\u{1fb7}', 4194371), + ('\u{1fbc}', 4194372), ('\u{1fbe}', 921), ('\u{1fc2}', 4194373), ('\u{1fc3}', 4194374), + ('\u{1fc4}', 4194375), ('\u{1fc6}', 4194376), ('\u{1fc7}', 4194377), ('\u{1fcc}', 4194378), + ('\u{1fd0}', 8152), ('\u{1fd1}', 8153), ('\u{1fd2}', 4194379), ('\u{1fd3}', 4194380), + ('\u{1fd6}', 4194381), ('\u{1fd7}', 4194382), ('\u{1fe0}', 8168), ('\u{1fe1}', 8169), + ('\u{1fe2}', 4194383), ('\u{1fe3}', 4194384), ('\u{1fe4}', 4194385), ('\u{1fe5}', 8172), + ('\u{1fe6}', 4194386), ('\u{1fe7}', 4194387), ('\u{1ff2}', 4194388), ('\u{1ff3}', 4194389), + ('\u{1ff4}', 4194390), ('\u{1ff6}', 4194391), ('\u{1ff7}', 4194392), ('\u{1ffc}', 4194393), + ('\u{214e}', 8498), ('\u{2170}', 8544), ('\u{2171}', 8545), ('\u{2172}', 8546), + ('\u{2173}', 8547), ('\u{2174}', 8548), ('\u{2175}', 8549), ('\u{2176}', 8550), + ('\u{2177}', 8551), ('\u{2178}', 8552), ('\u{2179}', 8553), ('\u{217a}', 8554), + ('\u{217b}', 8555), ('\u{217c}', 8556), ('\u{217d}', 8557), ('\u{217e}', 8558), + ('\u{217f}', 8559), ('\u{2184}', 8579), ('\u{24d0}', 9398), ('\u{24d1}', 9399), + ('\u{24d2}', 9400), ('\u{24d3}', 9401), ('\u{24d4}', 9402), ('\u{24d5}', 9403), + ('\u{24d6}', 9404), ('\u{24d7}', 9405), ('\u{24d8}', 9406), ('\u{24d9}', 9407), + ('\u{24da}', 9408), ('\u{24db}', 9409), ('\u{24dc}', 9410), ('\u{24dd}', 9411), + ('\u{24de}', 9412), ('\u{24df}', 9413), ('\u{24e0}', 9414), ('\u{24e1}', 9415), + ('\u{24e2}', 9416), ('\u{24e3}', 9417), ('\u{24e4}', 9418), ('\u{24e5}', 9419), + ('\u{24e6}', 9420), ('\u{24e7}', 9421), ('\u{24e8}', 9422), ('\u{24e9}', 9423), + ('\u{2c30}', 11264), ('\u{2c31}', 11265), ('\u{2c32}', 11266), ('\u{2c33}', 11267), + ('\u{2c34}', 11268), ('\u{2c35}', 11269), ('\u{2c36}', 11270), ('\u{2c37}', 11271), + ('\u{2c38}', 11272), ('\u{2c39}', 11273), ('\u{2c3a}', 11274), ('\u{2c3b}', 11275), + ('\u{2c3c}', 11276), ('\u{2c3d}', 11277), ('\u{2c3e}', 11278), ('\u{2c3f}', 11279), + ('\u{2c40}', 11280), ('\u{2c41}', 11281), ('\u{2c42}', 11282), ('\u{2c43}', 11283), + ('\u{2c44}', 11284), ('\u{2c45}', 11285), ('\u{2c46}', 11286), ('\u{2c47}', 11287), + ('\u{2c48}', 11288), ('\u{2c49}', 11289), ('\u{2c4a}', 11290), ('\u{2c4b}', 11291), + ('\u{2c4c}', 11292), ('\u{2c4d}', 11293), ('\u{2c4e}', 11294), ('\u{2c4f}', 11295), + ('\u{2c50}', 11296), ('\u{2c51}', 11297), ('\u{2c52}', 11298), ('\u{2c53}', 11299), + ('\u{2c54}', 11300), ('\u{2c55}', 11301), ('\u{2c56}', 11302), ('\u{2c57}', 11303), + ('\u{2c58}', 11304), ('\u{2c59}', 11305), ('\u{2c5a}', 11306), ('\u{2c5b}', 11307), + ('\u{2c5c}', 11308), ('\u{2c5d}', 11309), ('\u{2c5e}', 11310), ('\u{2c5f}', 11311), + ('\u{2c61}', 11360), ('\u{2c65}', 570), ('\u{2c66}', 574), ('\u{2c68}', 11367), + ('\u{2c6a}', 11369), ('\u{2c6c}', 11371), ('\u{2c73}', 11378), ('\u{2c76}', 11381), + ('\u{2c81}', 11392), ('\u{2c83}', 11394), ('\u{2c85}', 11396), ('\u{2c87}', 11398), + ('\u{2c89}', 11400), ('\u{2c8b}', 11402), ('\u{2c8d}', 11404), ('\u{2c8f}', 11406), + ('\u{2c91}', 11408), ('\u{2c93}', 11410), ('\u{2c95}', 11412), ('\u{2c97}', 11414), + ('\u{2c99}', 11416), ('\u{2c9b}', 11418), ('\u{2c9d}', 11420), ('\u{2c9f}', 11422), + ('\u{2ca1}', 11424), ('\u{2ca3}', 11426), ('\u{2ca5}', 11428), ('\u{2ca7}', 11430), + ('\u{2ca9}', 11432), ('\u{2cab}', 11434), ('\u{2cad}', 11436), ('\u{2caf}', 11438), + ('\u{2cb1}', 11440), ('\u{2cb3}', 11442), ('\u{2cb5}', 11444), ('\u{2cb7}', 11446), + ('\u{2cb9}', 11448), ('\u{2cbb}', 11450), ('\u{2cbd}', 11452), ('\u{2cbf}', 11454), + ('\u{2cc1}', 11456), ('\u{2cc3}', 11458), ('\u{2cc5}', 11460), ('\u{2cc7}', 11462), + ('\u{2cc9}', 11464), ('\u{2ccb}', 11466), ('\u{2ccd}', 11468), ('\u{2ccf}', 11470), + ('\u{2cd1}', 11472), ('\u{2cd3}', 11474), ('\u{2cd5}', 11476), ('\u{2cd7}', 11478), + ('\u{2cd9}', 11480), ('\u{2cdb}', 11482), ('\u{2cdd}', 11484), ('\u{2cdf}', 11486), + ('\u{2ce1}', 11488), ('\u{2ce3}', 11490), ('\u{2cec}', 11499), ('\u{2cee}', 11501), + ('\u{2cf3}', 11506), ('\u{2d00}', 4256), ('\u{2d01}', 4257), ('\u{2d02}', 4258), + ('\u{2d03}', 4259), ('\u{2d04}', 4260), ('\u{2d05}', 4261), ('\u{2d06}', 4262), + ('\u{2d07}', 4263), ('\u{2d08}', 4264), ('\u{2d09}', 4265), ('\u{2d0a}', 4266), + ('\u{2d0b}', 4267), ('\u{2d0c}', 4268), ('\u{2d0d}', 4269), ('\u{2d0e}', 4270), + ('\u{2d0f}', 4271), ('\u{2d10}', 4272), ('\u{2d11}', 4273), ('\u{2d12}', 4274), + ('\u{2d13}', 4275), ('\u{2d14}', 4276), ('\u{2d15}', 4277), ('\u{2d16}', 4278), + ('\u{2d17}', 4279), ('\u{2d18}', 4280), ('\u{2d19}', 4281), ('\u{2d1a}', 4282), + ('\u{2d1b}', 4283), ('\u{2d1c}', 4284), ('\u{2d1d}', 4285), ('\u{2d1e}', 4286), + ('\u{2d1f}', 4287), ('\u{2d20}', 4288), ('\u{2d21}', 4289), ('\u{2d22}', 4290), + ('\u{2d23}', 4291), ('\u{2d24}', 4292), ('\u{2d25}', 4293), ('\u{2d27}', 4295), + ('\u{2d2d}', 4301), ('\u{a641}', 42560), ('\u{a643}', 42562), ('\u{a645}', 42564), + ('\u{a647}', 42566), ('\u{a649}', 42568), ('\u{a64b}', 42570), ('\u{a64d}', 42572), + ('\u{a64f}', 42574), ('\u{a651}', 42576), ('\u{a653}', 42578), ('\u{a655}', 42580), + ('\u{a657}', 42582), ('\u{a659}', 42584), ('\u{a65b}', 42586), ('\u{a65d}', 42588), + ('\u{a65f}', 42590), ('\u{a661}', 42592), ('\u{a663}', 42594), ('\u{a665}', 42596), + ('\u{a667}', 42598), ('\u{a669}', 42600), ('\u{a66b}', 42602), ('\u{a66d}', 42604), + ('\u{a681}', 42624), ('\u{a683}', 42626), ('\u{a685}', 42628), ('\u{a687}', 42630), + ('\u{a689}', 42632), ('\u{a68b}', 42634), ('\u{a68d}', 42636), ('\u{a68f}', 42638), + ('\u{a691}', 42640), ('\u{a693}', 42642), ('\u{a695}', 42644), ('\u{a697}', 42646), + ('\u{a699}', 42648), ('\u{a69b}', 42650), ('\u{a723}', 42786), ('\u{a725}', 42788), + ('\u{a727}', 42790), ('\u{a729}', 42792), ('\u{a72b}', 42794), ('\u{a72d}', 42796), + ('\u{a72f}', 42798), ('\u{a733}', 42802), ('\u{a735}', 42804), ('\u{a737}', 42806), + ('\u{a739}', 42808), ('\u{a73b}', 42810), ('\u{a73d}', 42812), ('\u{a73f}', 42814), + ('\u{a741}', 42816), ('\u{a743}', 42818), ('\u{a745}', 42820), ('\u{a747}', 42822), + ('\u{a749}', 42824), ('\u{a74b}', 42826), ('\u{a74d}', 42828), ('\u{a74f}', 42830), + ('\u{a751}', 42832), ('\u{a753}', 42834), ('\u{a755}', 42836), ('\u{a757}', 42838), + ('\u{a759}', 42840), ('\u{a75b}', 42842), ('\u{a75d}', 42844), ('\u{a75f}', 42846), + ('\u{a761}', 42848), ('\u{a763}', 42850), ('\u{a765}', 42852), ('\u{a767}', 42854), + ('\u{a769}', 42856), ('\u{a76b}', 42858), ('\u{a76d}', 42860), ('\u{a76f}', 42862), + ('\u{a77a}', 42873), ('\u{a77c}', 42875), ('\u{a77f}', 42878), ('\u{a781}', 42880), + ('\u{a783}', 42882), ('\u{a785}', 42884), ('\u{a787}', 42886), ('\u{a78c}', 42891), + ('\u{a791}', 42896), ('\u{a793}', 42898), ('\u{a794}', 42948), ('\u{a797}', 42902), + ('\u{a799}', 42904), ('\u{a79b}', 42906), ('\u{a79d}', 42908), ('\u{a79f}', 42910), + ('\u{a7a1}', 42912), ('\u{a7a3}', 42914), ('\u{a7a5}', 42916), ('\u{a7a7}', 42918), + ('\u{a7a9}', 42920), ('\u{a7b5}', 42932), ('\u{a7b7}', 42934), ('\u{a7b9}', 42936), + ('\u{a7bb}', 42938), ('\u{a7bd}', 42940), ('\u{a7bf}', 42942), ('\u{a7c1}', 42944), + ('\u{a7c3}', 42946), ('\u{a7c8}', 42951), ('\u{a7ca}', 42953), ('\u{a7d1}', 42960), + ('\u{a7d7}', 42966), ('\u{a7d9}', 42968), ('\u{a7f6}', 42997), ('\u{ab53}', 42931), + ('\u{ab70}', 5024), ('\u{ab71}', 5025), ('\u{ab72}', 5026), ('\u{ab73}', 5027), + ('\u{ab74}', 5028), ('\u{ab75}', 5029), ('\u{ab76}', 5030), ('\u{ab77}', 5031), + ('\u{ab78}', 5032), ('\u{ab79}', 5033), ('\u{ab7a}', 5034), ('\u{ab7b}', 5035), + ('\u{ab7c}', 5036), ('\u{ab7d}', 5037), ('\u{ab7e}', 5038), ('\u{ab7f}', 5039), + ('\u{ab80}', 5040), ('\u{ab81}', 5041), ('\u{ab82}', 5042), ('\u{ab83}', 5043), + ('\u{ab84}', 5044), ('\u{ab85}', 5045), ('\u{ab86}', 5046), ('\u{ab87}', 5047), + ('\u{ab88}', 5048), ('\u{ab89}', 5049), ('\u{ab8a}', 5050), ('\u{ab8b}', 5051), + ('\u{ab8c}', 5052), ('\u{ab8d}', 5053), ('\u{ab8e}', 5054), ('\u{ab8f}', 5055), + ('\u{ab90}', 5056), ('\u{ab91}', 5057), ('\u{ab92}', 5058), ('\u{ab93}', 5059), + ('\u{ab94}', 5060), ('\u{ab95}', 5061), ('\u{ab96}', 5062), ('\u{ab97}', 5063), + ('\u{ab98}', 5064), ('\u{ab99}', 5065), ('\u{ab9a}', 5066), ('\u{ab9b}', 5067), + ('\u{ab9c}', 5068), ('\u{ab9d}', 5069), ('\u{ab9e}', 5070), ('\u{ab9f}', 5071), + ('\u{aba0}', 5072), ('\u{aba1}', 5073), ('\u{aba2}', 5074), ('\u{aba3}', 5075), + ('\u{aba4}', 5076), ('\u{aba5}', 5077), ('\u{aba6}', 5078), ('\u{aba7}', 5079), + ('\u{aba8}', 5080), ('\u{aba9}', 5081), ('\u{abaa}', 5082), ('\u{abab}', 5083), + ('\u{abac}', 5084), ('\u{abad}', 5085), ('\u{abae}', 5086), ('\u{abaf}', 5087), + ('\u{abb0}', 5088), ('\u{abb1}', 5089), ('\u{abb2}', 5090), ('\u{abb3}', 5091), + ('\u{abb4}', 5092), ('\u{abb5}', 5093), ('\u{abb6}', 5094), ('\u{abb7}', 5095), + ('\u{abb8}', 5096), ('\u{abb9}', 5097), ('\u{abba}', 5098), ('\u{abbb}', 5099), + ('\u{abbc}', 5100), ('\u{abbd}', 5101), ('\u{abbe}', 5102), ('\u{abbf}', 5103), + ('\u{fb00}', 4194394), ('\u{fb01}', 4194395), ('\u{fb02}', 4194396), ('\u{fb03}', 4194397), + ('\u{fb04}', 4194398), ('\u{fb05}', 4194399), ('\u{fb06}', 4194400), ('\u{fb13}', 4194401), + ('\u{fb14}', 4194402), ('\u{fb15}', 4194403), ('\u{fb16}', 4194404), ('\u{fb17}', 4194405), + ('\u{ff41}', 65313), ('\u{ff42}', 65314), ('\u{ff43}', 65315), ('\u{ff44}', 65316), + ('\u{ff45}', 65317), ('\u{ff46}', 65318), ('\u{ff47}', 65319), ('\u{ff48}', 65320), + ('\u{ff49}', 65321), ('\u{ff4a}', 65322), ('\u{ff4b}', 65323), ('\u{ff4c}', 65324), + ('\u{ff4d}', 65325), ('\u{ff4e}', 65326), ('\u{ff4f}', 65327), ('\u{ff50}', 65328), + ('\u{ff51}', 65329), ('\u{ff52}', 65330), ('\u{ff53}', 65331), ('\u{ff54}', 65332), + ('\u{ff55}', 65333), ('\u{ff56}', 65334), ('\u{ff57}', 65335), ('\u{ff58}', 65336), + ('\u{ff59}', 65337), ('\u{ff5a}', 65338), ('\u{10428}', 66560), ('\u{10429}', 66561), + ('\u{1042a}', 66562), ('\u{1042b}', 66563), ('\u{1042c}', 66564), ('\u{1042d}', 66565), + ('\u{1042e}', 66566), ('\u{1042f}', 66567), ('\u{10430}', 66568), ('\u{10431}', 66569), + ('\u{10432}', 66570), ('\u{10433}', 66571), ('\u{10434}', 66572), ('\u{10435}', 66573), + ('\u{10436}', 66574), ('\u{10437}', 66575), ('\u{10438}', 66576), ('\u{10439}', 66577), + ('\u{1043a}', 66578), ('\u{1043b}', 66579), ('\u{1043c}', 66580), ('\u{1043d}', 66581), + ('\u{1043e}', 66582), ('\u{1043f}', 66583), ('\u{10440}', 66584), ('\u{10441}', 66585), + ('\u{10442}', 66586), ('\u{10443}', 66587), ('\u{10444}', 66588), ('\u{10445}', 66589), + ('\u{10446}', 66590), ('\u{10447}', 66591), ('\u{10448}', 66592), ('\u{10449}', 66593), + ('\u{1044a}', 66594), ('\u{1044b}', 66595), ('\u{1044c}', 66596), ('\u{1044d}', 66597), + ('\u{1044e}', 66598), ('\u{1044f}', 66599), ('\u{104d8}', 66736), ('\u{104d9}', 66737), + ('\u{104da}', 66738), ('\u{104db}', 66739), ('\u{104dc}', 66740), ('\u{104dd}', 66741), + ('\u{104de}', 66742), ('\u{104df}', 66743), ('\u{104e0}', 66744), ('\u{104e1}', 66745), + ('\u{104e2}', 66746), ('\u{104e3}', 66747), ('\u{104e4}', 66748), ('\u{104e5}', 66749), + ('\u{104e6}', 66750), ('\u{104e7}', 66751), ('\u{104e8}', 66752), ('\u{104e9}', 66753), + ('\u{104ea}', 66754), ('\u{104eb}', 66755), ('\u{104ec}', 66756), ('\u{104ed}', 66757), + ('\u{104ee}', 66758), ('\u{104ef}', 66759), ('\u{104f0}', 66760), ('\u{104f1}', 66761), + ('\u{104f2}', 66762), ('\u{104f3}', 66763), ('\u{104f4}', 66764), ('\u{104f5}', 66765), + ('\u{104f6}', 66766), ('\u{104f7}', 66767), ('\u{104f8}', 66768), ('\u{104f9}', 66769), + ('\u{104fa}', 66770), ('\u{104fb}', 66771), ('\u{10597}', 66928), ('\u{10598}', 66929), + ('\u{10599}', 66930), ('\u{1059a}', 66931), ('\u{1059b}', 66932), ('\u{1059c}', 66933), + ('\u{1059d}', 66934), ('\u{1059e}', 66935), ('\u{1059f}', 66936), ('\u{105a0}', 66937), + ('\u{105a1}', 66938), ('\u{105a3}', 66940), ('\u{105a4}', 66941), ('\u{105a5}', 66942), + ('\u{105a6}', 66943), ('\u{105a7}', 66944), ('\u{105a8}', 66945), ('\u{105a9}', 66946), + ('\u{105aa}', 66947), ('\u{105ab}', 66948), ('\u{105ac}', 66949), ('\u{105ad}', 66950), + ('\u{105ae}', 66951), ('\u{105af}', 66952), ('\u{105b0}', 66953), ('\u{105b1}', 66954), + ('\u{105b3}', 66956), ('\u{105b4}', 66957), ('\u{105b5}', 66958), ('\u{105b6}', 66959), + ('\u{105b7}', 66960), ('\u{105b8}', 66961), ('\u{105b9}', 66962), ('\u{105bb}', 66964), + ('\u{105bc}', 66965), ('\u{10cc0}', 68736), ('\u{10cc1}', 68737), ('\u{10cc2}', 68738), + ('\u{10cc3}', 68739), ('\u{10cc4}', 68740), ('\u{10cc5}', 68741), ('\u{10cc6}', 68742), + ('\u{10cc7}', 68743), ('\u{10cc8}', 68744), ('\u{10cc9}', 68745), ('\u{10cca}', 68746), + ('\u{10ccb}', 68747), ('\u{10ccc}', 68748), ('\u{10ccd}', 68749), ('\u{10cce}', 68750), + ('\u{10ccf}', 68751), ('\u{10cd0}', 68752), ('\u{10cd1}', 68753), ('\u{10cd2}', 68754), + ('\u{10cd3}', 68755), ('\u{10cd4}', 68756), ('\u{10cd5}', 68757), ('\u{10cd6}', 68758), + ('\u{10cd7}', 68759), ('\u{10cd8}', 68760), ('\u{10cd9}', 68761), ('\u{10cda}', 68762), + ('\u{10cdb}', 68763), ('\u{10cdc}', 68764), ('\u{10cdd}', 68765), ('\u{10cde}', 68766), + ('\u{10cdf}', 68767), ('\u{10ce0}', 68768), ('\u{10ce1}', 68769), ('\u{10ce2}', 68770), + ('\u{10ce3}', 68771), ('\u{10ce4}', 68772), ('\u{10ce5}', 68773), ('\u{10ce6}', 68774), + ('\u{10ce7}', 68775), ('\u{10ce8}', 68776), ('\u{10ce9}', 68777), ('\u{10cea}', 68778), + ('\u{10ceb}', 68779), ('\u{10cec}', 68780), ('\u{10ced}', 68781), ('\u{10cee}', 68782), + ('\u{10cef}', 68783), ('\u{10cf0}', 68784), ('\u{10cf1}', 68785), ('\u{10cf2}', 68786), + ('\u{118c0}', 71840), ('\u{118c1}', 71841), ('\u{118c2}', 71842), ('\u{118c3}', 71843), + ('\u{118c4}', 71844), ('\u{118c5}', 71845), ('\u{118c6}', 71846), ('\u{118c7}', 71847), + ('\u{118c8}', 71848), ('\u{118c9}', 71849), ('\u{118ca}', 71850), ('\u{118cb}', 71851), + ('\u{118cc}', 71852), ('\u{118cd}', 71853), ('\u{118ce}', 71854), ('\u{118cf}', 71855), + ('\u{118d0}', 71856), ('\u{118d1}', 71857), ('\u{118d2}', 71858), ('\u{118d3}', 71859), + ('\u{118d4}', 71860), ('\u{118d5}', 71861), ('\u{118d6}', 71862), ('\u{118d7}', 71863), + ('\u{118d8}', 71864), ('\u{118d9}', 71865), ('\u{118da}', 71866), ('\u{118db}', 71867), + ('\u{118dc}', 71868), ('\u{118dd}', 71869), ('\u{118de}', 71870), ('\u{118df}', 71871), + ('\u{16e60}', 93760), ('\u{16e61}', 93761), ('\u{16e62}', 93762), ('\u{16e63}', 93763), + ('\u{16e64}', 93764), ('\u{16e65}', 93765), ('\u{16e66}', 93766), ('\u{16e67}', 93767), + ('\u{16e68}', 93768), ('\u{16e69}', 93769), ('\u{16e6a}', 93770), ('\u{16e6b}', 93771), + ('\u{16e6c}', 93772), ('\u{16e6d}', 93773), ('\u{16e6e}', 93774), ('\u{16e6f}', 93775), + ('\u{16e70}', 93776), ('\u{16e71}', 93777), ('\u{16e72}', 93778), ('\u{16e73}', 93779), + ('\u{16e74}', 93780), ('\u{16e75}', 93781), ('\u{16e76}', 93782), ('\u{16e77}', 93783), + ('\u{16e78}', 93784), ('\u{16e79}', 93785), ('\u{16e7a}', 93786), ('\u{16e7b}', 93787), + ('\u{16e7c}', 93788), ('\u{16e7d}', 93789), ('\u{16e7e}', 93790), ('\u{16e7f}', 93791), + ('\u{1e922}', 125184), ('\u{1e923}', 125185), ('\u{1e924}', 125186), ('\u{1e925}', 125187), + ('\u{1e926}', 125188), ('\u{1e927}', 125189), ('\u{1e928}', 125190), ('\u{1e929}', 125191), + ('\u{1e92a}', 125192), ('\u{1e92b}', 125193), ('\u{1e92c}', 125194), ('\u{1e92d}', 125195), + ('\u{1e92e}', 125196), ('\u{1e92f}', 125197), ('\u{1e930}', 125198), ('\u{1e931}', 125199), + ('\u{1e932}', 125200), ('\u{1e933}', 125201), ('\u{1e934}', 125202), ('\u{1e935}', 125203), + ('\u{1e936}', 125204), ('\u{1e937}', 125205), ('\u{1e938}', 125206), ('\u{1e939}', 125207), + ('\u{1e93a}', 125208), ('\u{1e93b}', 125209), ('\u{1e93c}', 125210), ('\u{1e93d}', 125211), + ('\u{1e93e}', 125212), ('\u{1e93f}', 125213), ('\u{1e940}', 125214), ('\u{1e941}', 125215), + ('\u{1e942}', 125216), ('\u{1e943}', 125217), ]; - static UPPERCASE_TABLE: &[(char, [char; 3])] = &[ - ('a', ['A', '\u{0}', '\u{0}']), ('b', ['B', '\u{0}', '\u{0}']), - ('c', ['C', '\u{0}', '\u{0}']), ('d', ['D', '\u{0}', '\u{0}']), - ('e', ['E', '\u{0}', '\u{0}']), ('f', ['F', '\u{0}', '\u{0}']), - ('g', ['G', '\u{0}', '\u{0}']), ('h', ['H', '\u{0}', '\u{0}']), - ('i', ['I', '\u{0}', '\u{0}']), ('j', ['J', '\u{0}', '\u{0}']), - ('k', ['K', '\u{0}', '\u{0}']), ('l', ['L', '\u{0}', '\u{0}']), - ('m', ['M', '\u{0}', '\u{0}']), ('n', ['N', '\u{0}', '\u{0}']), - ('o', ['O', '\u{0}', '\u{0}']), ('p', ['P', '\u{0}', '\u{0}']), - ('q', ['Q', '\u{0}', '\u{0}']), ('r', ['R', '\u{0}', '\u{0}']), - ('s', ['S', '\u{0}', '\u{0}']), ('t', ['T', '\u{0}', '\u{0}']), - ('u', ['U', '\u{0}', '\u{0}']), ('v', ['V', '\u{0}', '\u{0}']), - ('w', ['W', '\u{0}', '\u{0}']), ('x', ['X', '\u{0}', '\u{0}']), - ('y', ['Y', '\u{0}', '\u{0}']), ('z', ['Z', '\u{0}', '\u{0}']), - ('\u{b5}', ['\u{39c}', '\u{0}', '\u{0}']), ('\u{df}', ['S', 'S', '\u{0}']), - ('\u{e0}', ['\u{c0}', '\u{0}', '\u{0}']), ('\u{e1}', ['\u{c1}', '\u{0}', '\u{0}']), - ('\u{e2}', ['\u{c2}', '\u{0}', '\u{0}']), ('\u{e3}', ['\u{c3}', '\u{0}', '\u{0}']), - ('\u{e4}', ['\u{c4}', '\u{0}', '\u{0}']), ('\u{e5}', ['\u{c5}', '\u{0}', '\u{0}']), - ('\u{e6}', ['\u{c6}', '\u{0}', '\u{0}']), ('\u{e7}', ['\u{c7}', '\u{0}', '\u{0}']), - ('\u{e8}', ['\u{c8}', '\u{0}', '\u{0}']), ('\u{e9}', ['\u{c9}', '\u{0}', '\u{0}']), - ('\u{ea}', ['\u{ca}', '\u{0}', '\u{0}']), ('\u{eb}', ['\u{cb}', '\u{0}', '\u{0}']), - ('\u{ec}', ['\u{cc}', '\u{0}', '\u{0}']), ('\u{ed}', ['\u{cd}', '\u{0}', '\u{0}']), - ('\u{ee}', ['\u{ce}', '\u{0}', '\u{0}']), ('\u{ef}', ['\u{cf}', '\u{0}', '\u{0}']), - ('\u{f0}', ['\u{d0}', '\u{0}', '\u{0}']), ('\u{f1}', ['\u{d1}', '\u{0}', '\u{0}']), - ('\u{f2}', ['\u{d2}', '\u{0}', '\u{0}']), ('\u{f3}', ['\u{d3}', '\u{0}', '\u{0}']), - ('\u{f4}', ['\u{d4}', '\u{0}', '\u{0}']), ('\u{f5}', ['\u{d5}', '\u{0}', '\u{0}']), - ('\u{f6}', ['\u{d6}', '\u{0}', '\u{0}']), ('\u{f8}', ['\u{d8}', '\u{0}', '\u{0}']), - ('\u{f9}', ['\u{d9}', '\u{0}', '\u{0}']), ('\u{fa}', ['\u{da}', '\u{0}', '\u{0}']), - ('\u{fb}', ['\u{db}', '\u{0}', '\u{0}']), ('\u{fc}', ['\u{dc}', '\u{0}', '\u{0}']), - ('\u{fd}', ['\u{dd}', '\u{0}', '\u{0}']), ('\u{fe}', ['\u{de}', '\u{0}', '\u{0}']), - ('\u{ff}', ['\u{178}', '\u{0}', '\u{0}']), ('\u{101}', ['\u{100}', '\u{0}', '\u{0}']), - ('\u{103}', ['\u{102}', '\u{0}', '\u{0}']), ('\u{105}', ['\u{104}', '\u{0}', '\u{0}']), - ('\u{107}', ['\u{106}', '\u{0}', '\u{0}']), ('\u{109}', ['\u{108}', '\u{0}', '\u{0}']), - ('\u{10b}', ['\u{10a}', '\u{0}', '\u{0}']), ('\u{10d}', ['\u{10c}', '\u{0}', '\u{0}']), - ('\u{10f}', ['\u{10e}', '\u{0}', '\u{0}']), ('\u{111}', ['\u{110}', '\u{0}', '\u{0}']), - ('\u{113}', ['\u{112}', '\u{0}', '\u{0}']), ('\u{115}', ['\u{114}', '\u{0}', '\u{0}']), - ('\u{117}', ['\u{116}', '\u{0}', '\u{0}']), ('\u{119}', ['\u{118}', '\u{0}', '\u{0}']), - ('\u{11b}', ['\u{11a}', '\u{0}', '\u{0}']), ('\u{11d}', ['\u{11c}', '\u{0}', '\u{0}']), - ('\u{11f}', ['\u{11e}', '\u{0}', '\u{0}']), ('\u{121}', ['\u{120}', '\u{0}', '\u{0}']), - ('\u{123}', ['\u{122}', '\u{0}', '\u{0}']), ('\u{125}', ['\u{124}', '\u{0}', '\u{0}']), - ('\u{127}', ['\u{126}', '\u{0}', '\u{0}']), ('\u{129}', ['\u{128}', '\u{0}', '\u{0}']), - ('\u{12b}', ['\u{12a}', '\u{0}', '\u{0}']), ('\u{12d}', ['\u{12c}', '\u{0}', '\u{0}']), - ('\u{12f}', ['\u{12e}', '\u{0}', '\u{0}']), ('\u{131}', ['I', '\u{0}', '\u{0}']), - ('\u{133}', ['\u{132}', '\u{0}', '\u{0}']), ('\u{135}', ['\u{134}', '\u{0}', '\u{0}']), - ('\u{137}', ['\u{136}', '\u{0}', '\u{0}']), ('\u{13a}', ['\u{139}', '\u{0}', '\u{0}']), - ('\u{13c}', ['\u{13b}', '\u{0}', '\u{0}']), ('\u{13e}', ['\u{13d}', '\u{0}', '\u{0}']), - ('\u{140}', ['\u{13f}', '\u{0}', '\u{0}']), ('\u{142}', ['\u{141}', '\u{0}', '\u{0}']), - ('\u{144}', ['\u{143}', '\u{0}', '\u{0}']), ('\u{146}', ['\u{145}', '\u{0}', '\u{0}']), - ('\u{148}', ['\u{147}', '\u{0}', '\u{0}']), ('\u{149}', ['\u{2bc}', 'N', '\u{0}']), - ('\u{14b}', ['\u{14a}', '\u{0}', '\u{0}']), ('\u{14d}', ['\u{14c}', '\u{0}', '\u{0}']), - ('\u{14f}', ['\u{14e}', '\u{0}', '\u{0}']), ('\u{151}', ['\u{150}', '\u{0}', '\u{0}']), - ('\u{153}', ['\u{152}', '\u{0}', '\u{0}']), ('\u{155}', ['\u{154}', '\u{0}', '\u{0}']), - ('\u{157}', ['\u{156}', '\u{0}', '\u{0}']), ('\u{159}', ['\u{158}', '\u{0}', '\u{0}']), - ('\u{15b}', ['\u{15a}', '\u{0}', '\u{0}']), ('\u{15d}', ['\u{15c}', '\u{0}', '\u{0}']), - ('\u{15f}', ['\u{15e}', '\u{0}', '\u{0}']), ('\u{161}', ['\u{160}', '\u{0}', '\u{0}']), - ('\u{163}', ['\u{162}', '\u{0}', '\u{0}']), ('\u{165}', ['\u{164}', '\u{0}', '\u{0}']), - ('\u{167}', ['\u{166}', '\u{0}', '\u{0}']), ('\u{169}', ['\u{168}', '\u{0}', '\u{0}']), - ('\u{16b}', ['\u{16a}', '\u{0}', '\u{0}']), ('\u{16d}', ['\u{16c}', '\u{0}', '\u{0}']), - ('\u{16f}', ['\u{16e}', '\u{0}', '\u{0}']), ('\u{171}', ['\u{170}', '\u{0}', '\u{0}']), - ('\u{173}', ['\u{172}', '\u{0}', '\u{0}']), ('\u{175}', ['\u{174}', '\u{0}', '\u{0}']), - ('\u{177}', ['\u{176}', '\u{0}', '\u{0}']), ('\u{17a}', ['\u{179}', '\u{0}', '\u{0}']), - ('\u{17c}', ['\u{17b}', '\u{0}', '\u{0}']), ('\u{17e}', ['\u{17d}', '\u{0}', '\u{0}']), - ('\u{17f}', ['S', '\u{0}', '\u{0}']), ('\u{180}', ['\u{243}', '\u{0}', '\u{0}']), - ('\u{183}', ['\u{182}', '\u{0}', '\u{0}']), ('\u{185}', ['\u{184}', '\u{0}', '\u{0}']), - ('\u{188}', ['\u{187}', '\u{0}', '\u{0}']), ('\u{18c}', ['\u{18b}', '\u{0}', '\u{0}']), - ('\u{192}', ['\u{191}', '\u{0}', '\u{0}']), ('\u{195}', ['\u{1f6}', '\u{0}', '\u{0}']), - ('\u{199}', ['\u{198}', '\u{0}', '\u{0}']), ('\u{19a}', ['\u{23d}', '\u{0}', '\u{0}']), - ('\u{19e}', ['\u{220}', '\u{0}', '\u{0}']), ('\u{1a1}', ['\u{1a0}', '\u{0}', '\u{0}']), - ('\u{1a3}', ['\u{1a2}', '\u{0}', '\u{0}']), ('\u{1a5}', ['\u{1a4}', '\u{0}', '\u{0}']), - ('\u{1a8}', ['\u{1a7}', '\u{0}', '\u{0}']), ('\u{1ad}', ['\u{1ac}', '\u{0}', '\u{0}']), - ('\u{1b0}', ['\u{1af}', '\u{0}', '\u{0}']), ('\u{1b4}', ['\u{1b3}', '\u{0}', '\u{0}']), - ('\u{1b6}', ['\u{1b5}', '\u{0}', '\u{0}']), ('\u{1b9}', ['\u{1b8}', '\u{0}', '\u{0}']), - ('\u{1bd}', ['\u{1bc}', '\u{0}', '\u{0}']), ('\u{1bf}', ['\u{1f7}', '\u{0}', '\u{0}']), - ('\u{1c5}', ['\u{1c4}', '\u{0}', '\u{0}']), ('\u{1c6}', ['\u{1c4}', '\u{0}', '\u{0}']), - ('\u{1c8}', ['\u{1c7}', '\u{0}', '\u{0}']), ('\u{1c9}', ['\u{1c7}', '\u{0}', '\u{0}']), - ('\u{1cb}', ['\u{1ca}', '\u{0}', '\u{0}']), ('\u{1cc}', ['\u{1ca}', '\u{0}', '\u{0}']), - ('\u{1ce}', ['\u{1cd}', '\u{0}', '\u{0}']), ('\u{1d0}', ['\u{1cf}', '\u{0}', '\u{0}']), - ('\u{1d2}', ['\u{1d1}', '\u{0}', '\u{0}']), ('\u{1d4}', ['\u{1d3}', '\u{0}', '\u{0}']), - ('\u{1d6}', ['\u{1d5}', '\u{0}', '\u{0}']), ('\u{1d8}', ['\u{1d7}', '\u{0}', '\u{0}']), - ('\u{1da}', ['\u{1d9}', '\u{0}', '\u{0}']), ('\u{1dc}', ['\u{1db}', '\u{0}', '\u{0}']), - ('\u{1dd}', ['\u{18e}', '\u{0}', '\u{0}']), ('\u{1df}', ['\u{1de}', '\u{0}', '\u{0}']), - ('\u{1e1}', ['\u{1e0}', '\u{0}', '\u{0}']), ('\u{1e3}', ['\u{1e2}', '\u{0}', '\u{0}']), - ('\u{1e5}', ['\u{1e4}', '\u{0}', '\u{0}']), ('\u{1e7}', ['\u{1e6}', '\u{0}', '\u{0}']), - ('\u{1e9}', ['\u{1e8}', '\u{0}', '\u{0}']), ('\u{1eb}', ['\u{1ea}', '\u{0}', '\u{0}']), - ('\u{1ed}', ['\u{1ec}', '\u{0}', '\u{0}']), ('\u{1ef}', ['\u{1ee}', '\u{0}', '\u{0}']), - ('\u{1f0}', ['J', '\u{30c}', '\u{0}']), ('\u{1f2}', ['\u{1f1}', '\u{0}', '\u{0}']), - ('\u{1f3}', ['\u{1f1}', '\u{0}', '\u{0}']), ('\u{1f5}', ['\u{1f4}', '\u{0}', '\u{0}']), - ('\u{1f9}', ['\u{1f8}', '\u{0}', '\u{0}']), ('\u{1fb}', ['\u{1fa}', '\u{0}', '\u{0}']), - ('\u{1fd}', ['\u{1fc}', '\u{0}', '\u{0}']), ('\u{1ff}', ['\u{1fe}', '\u{0}', '\u{0}']), - ('\u{201}', ['\u{200}', '\u{0}', '\u{0}']), ('\u{203}', ['\u{202}', '\u{0}', '\u{0}']), - ('\u{205}', ['\u{204}', '\u{0}', '\u{0}']), ('\u{207}', ['\u{206}', '\u{0}', '\u{0}']), - ('\u{209}', ['\u{208}', '\u{0}', '\u{0}']), ('\u{20b}', ['\u{20a}', '\u{0}', '\u{0}']), - ('\u{20d}', ['\u{20c}', '\u{0}', '\u{0}']), ('\u{20f}', ['\u{20e}', '\u{0}', '\u{0}']), - ('\u{211}', ['\u{210}', '\u{0}', '\u{0}']), ('\u{213}', ['\u{212}', '\u{0}', '\u{0}']), - ('\u{215}', ['\u{214}', '\u{0}', '\u{0}']), ('\u{217}', ['\u{216}', '\u{0}', '\u{0}']), - ('\u{219}', ['\u{218}', '\u{0}', '\u{0}']), ('\u{21b}', ['\u{21a}', '\u{0}', '\u{0}']), - ('\u{21d}', ['\u{21c}', '\u{0}', '\u{0}']), ('\u{21f}', ['\u{21e}', '\u{0}', '\u{0}']), - ('\u{223}', ['\u{222}', '\u{0}', '\u{0}']), ('\u{225}', ['\u{224}', '\u{0}', '\u{0}']), - ('\u{227}', ['\u{226}', '\u{0}', '\u{0}']), ('\u{229}', ['\u{228}', '\u{0}', '\u{0}']), - ('\u{22b}', ['\u{22a}', '\u{0}', '\u{0}']), ('\u{22d}', ['\u{22c}', '\u{0}', '\u{0}']), - ('\u{22f}', ['\u{22e}', '\u{0}', '\u{0}']), ('\u{231}', ['\u{230}', '\u{0}', '\u{0}']), - ('\u{233}', ['\u{232}', '\u{0}', '\u{0}']), ('\u{23c}', ['\u{23b}', '\u{0}', '\u{0}']), - ('\u{23f}', ['\u{2c7e}', '\u{0}', '\u{0}']), ('\u{240}', ['\u{2c7f}', '\u{0}', '\u{0}']), - ('\u{242}', ['\u{241}', '\u{0}', '\u{0}']), ('\u{247}', ['\u{246}', '\u{0}', '\u{0}']), - ('\u{249}', ['\u{248}', '\u{0}', '\u{0}']), ('\u{24b}', ['\u{24a}', '\u{0}', '\u{0}']), - ('\u{24d}', ['\u{24c}', '\u{0}', '\u{0}']), ('\u{24f}', ['\u{24e}', '\u{0}', '\u{0}']), - ('\u{250}', ['\u{2c6f}', '\u{0}', '\u{0}']), ('\u{251}', ['\u{2c6d}', '\u{0}', '\u{0}']), - ('\u{252}', ['\u{2c70}', '\u{0}', '\u{0}']), ('\u{253}', ['\u{181}', '\u{0}', '\u{0}']), - ('\u{254}', ['\u{186}', '\u{0}', '\u{0}']), ('\u{256}', ['\u{189}', '\u{0}', '\u{0}']), - ('\u{257}', ['\u{18a}', '\u{0}', '\u{0}']), ('\u{259}', ['\u{18f}', '\u{0}', '\u{0}']), - ('\u{25b}', ['\u{190}', '\u{0}', '\u{0}']), ('\u{25c}', ['\u{a7ab}', '\u{0}', '\u{0}']), - ('\u{260}', ['\u{193}', '\u{0}', '\u{0}']), ('\u{261}', ['\u{a7ac}', '\u{0}', '\u{0}']), - ('\u{263}', ['\u{194}', '\u{0}', '\u{0}']), ('\u{265}', ['\u{a78d}', '\u{0}', '\u{0}']), - ('\u{266}', ['\u{a7aa}', '\u{0}', '\u{0}']), ('\u{268}', ['\u{197}', '\u{0}', '\u{0}']), - ('\u{269}', ['\u{196}', '\u{0}', '\u{0}']), ('\u{26a}', ['\u{a7ae}', '\u{0}', '\u{0}']), - ('\u{26b}', ['\u{2c62}', '\u{0}', '\u{0}']), ('\u{26c}', ['\u{a7ad}', '\u{0}', '\u{0}']), - ('\u{26f}', ['\u{19c}', '\u{0}', '\u{0}']), ('\u{271}', ['\u{2c6e}', '\u{0}', '\u{0}']), - ('\u{272}', ['\u{19d}', '\u{0}', '\u{0}']), ('\u{275}', ['\u{19f}', '\u{0}', '\u{0}']), - ('\u{27d}', ['\u{2c64}', '\u{0}', '\u{0}']), ('\u{280}', ['\u{1a6}', '\u{0}', '\u{0}']), - ('\u{282}', ['\u{a7c5}', '\u{0}', '\u{0}']), ('\u{283}', ['\u{1a9}', '\u{0}', '\u{0}']), - ('\u{287}', ['\u{a7b1}', '\u{0}', '\u{0}']), ('\u{288}', ['\u{1ae}', '\u{0}', '\u{0}']), - ('\u{289}', ['\u{244}', '\u{0}', '\u{0}']), ('\u{28a}', ['\u{1b1}', '\u{0}', '\u{0}']), - ('\u{28b}', ['\u{1b2}', '\u{0}', '\u{0}']), ('\u{28c}', ['\u{245}', '\u{0}', '\u{0}']), - ('\u{292}', ['\u{1b7}', '\u{0}', '\u{0}']), ('\u{29d}', ['\u{a7b2}', '\u{0}', '\u{0}']), - ('\u{29e}', ['\u{a7b0}', '\u{0}', '\u{0}']), ('\u{345}', ['\u{399}', '\u{0}', '\u{0}']), - ('\u{371}', ['\u{370}', '\u{0}', '\u{0}']), ('\u{373}', ['\u{372}', '\u{0}', '\u{0}']), - ('\u{377}', ['\u{376}', '\u{0}', '\u{0}']), ('\u{37b}', ['\u{3fd}', '\u{0}', '\u{0}']), - ('\u{37c}', ['\u{3fe}', '\u{0}', '\u{0}']), ('\u{37d}', ['\u{3ff}', '\u{0}', '\u{0}']), - ('\u{390}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{3ac}', ['\u{386}', '\u{0}', '\u{0}']), - ('\u{3ad}', ['\u{388}', '\u{0}', '\u{0}']), ('\u{3ae}', ['\u{389}', '\u{0}', '\u{0}']), - ('\u{3af}', ['\u{38a}', '\u{0}', '\u{0}']), ('\u{3b0}', ['\u{3a5}', '\u{308}', '\u{301}']), - ('\u{3b1}', ['\u{391}', '\u{0}', '\u{0}']), ('\u{3b2}', ['\u{392}', '\u{0}', '\u{0}']), - ('\u{3b3}', ['\u{393}', '\u{0}', '\u{0}']), ('\u{3b4}', ['\u{394}', '\u{0}', '\u{0}']), - ('\u{3b5}', ['\u{395}', '\u{0}', '\u{0}']), ('\u{3b6}', ['\u{396}', '\u{0}', '\u{0}']), - ('\u{3b7}', ['\u{397}', '\u{0}', '\u{0}']), ('\u{3b8}', ['\u{398}', '\u{0}', '\u{0}']), - ('\u{3b9}', ['\u{399}', '\u{0}', '\u{0}']), ('\u{3ba}', ['\u{39a}', '\u{0}', '\u{0}']), - ('\u{3bb}', ['\u{39b}', '\u{0}', '\u{0}']), ('\u{3bc}', ['\u{39c}', '\u{0}', '\u{0}']), - ('\u{3bd}', ['\u{39d}', '\u{0}', '\u{0}']), ('\u{3be}', ['\u{39e}', '\u{0}', '\u{0}']), - ('\u{3bf}', ['\u{39f}', '\u{0}', '\u{0}']), ('\u{3c0}', ['\u{3a0}', '\u{0}', '\u{0}']), - ('\u{3c1}', ['\u{3a1}', '\u{0}', '\u{0}']), ('\u{3c2}', ['\u{3a3}', '\u{0}', '\u{0}']), - ('\u{3c3}', ['\u{3a3}', '\u{0}', '\u{0}']), ('\u{3c4}', ['\u{3a4}', '\u{0}', '\u{0}']), - ('\u{3c5}', ['\u{3a5}', '\u{0}', '\u{0}']), ('\u{3c6}', ['\u{3a6}', '\u{0}', '\u{0}']), - ('\u{3c7}', ['\u{3a7}', '\u{0}', '\u{0}']), ('\u{3c8}', ['\u{3a8}', '\u{0}', '\u{0}']), - ('\u{3c9}', ['\u{3a9}', '\u{0}', '\u{0}']), ('\u{3ca}', ['\u{3aa}', '\u{0}', '\u{0}']), - ('\u{3cb}', ['\u{3ab}', '\u{0}', '\u{0}']), ('\u{3cc}', ['\u{38c}', '\u{0}', '\u{0}']), - ('\u{3cd}', ['\u{38e}', '\u{0}', '\u{0}']), ('\u{3ce}', ['\u{38f}', '\u{0}', '\u{0}']), - ('\u{3d0}', ['\u{392}', '\u{0}', '\u{0}']), ('\u{3d1}', ['\u{398}', '\u{0}', '\u{0}']), - ('\u{3d5}', ['\u{3a6}', '\u{0}', '\u{0}']), ('\u{3d6}', ['\u{3a0}', '\u{0}', '\u{0}']), - ('\u{3d7}', ['\u{3cf}', '\u{0}', '\u{0}']), ('\u{3d9}', ['\u{3d8}', '\u{0}', '\u{0}']), - ('\u{3db}', ['\u{3da}', '\u{0}', '\u{0}']), ('\u{3dd}', ['\u{3dc}', '\u{0}', '\u{0}']), - ('\u{3df}', ['\u{3de}', '\u{0}', '\u{0}']), ('\u{3e1}', ['\u{3e0}', '\u{0}', '\u{0}']), - ('\u{3e3}', ['\u{3e2}', '\u{0}', '\u{0}']), ('\u{3e5}', ['\u{3e4}', '\u{0}', '\u{0}']), - ('\u{3e7}', ['\u{3e6}', '\u{0}', '\u{0}']), ('\u{3e9}', ['\u{3e8}', '\u{0}', '\u{0}']), - ('\u{3eb}', ['\u{3ea}', '\u{0}', '\u{0}']), ('\u{3ed}', ['\u{3ec}', '\u{0}', '\u{0}']), - ('\u{3ef}', ['\u{3ee}', '\u{0}', '\u{0}']), ('\u{3f0}', ['\u{39a}', '\u{0}', '\u{0}']), - ('\u{3f1}', ['\u{3a1}', '\u{0}', '\u{0}']), ('\u{3f2}', ['\u{3f9}', '\u{0}', '\u{0}']), - ('\u{3f3}', ['\u{37f}', '\u{0}', '\u{0}']), ('\u{3f5}', ['\u{395}', '\u{0}', '\u{0}']), - ('\u{3f8}', ['\u{3f7}', '\u{0}', '\u{0}']), ('\u{3fb}', ['\u{3fa}', '\u{0}', '\u{0}']), - ('\u{430}', ['\u{410}', '\u{0}', '\u{0}']), ('\u{431}', ['\u{411}', '\u{0}', '\u{0}']), - ('\u{432}', ['\u{412}', '\u{0}', '\u{0}']), ('\u{433}', ['\u{413}', '\u{0}', '\u{0}']), - ('\u{434}', ['\u{414}', '\u{0}', '\u{0}']), ('\u{435}', ['\u{415}', '\u{0}', '\u{0}']), - ('\u{436}', ['\u{416}', '\u{0}', '\u{0}']), ('\u{437}', ['\u{417}', '\u{0}', '\u{0}']), - ('\u{438}', ['\u{418}', '\u{0}', '\u{0}']), ('\u{439}', ['\u{419}', '\u{0}', '\u{0}']), - ('\u{43a}', ['\u{41a}', '\u{0}', '\u{0}']), ('\u{43b}', ['\u{41b}', '\u{0}', '\u{0}']), - ('\u{43c}', ['\u{41c}', '\u{0}', '\u{0}']), ('\u{43d}', ['\u{41d}', '\u{0}', '\u{0}']), - ('\u{43e}', ['\u{41e}', '\u{0}', '\u{0}']), ('\u{43f}', ['\u{41f}', '\u{0}', '\u{0}']), - ('\u{440}', ['\u{420}', '\u{0}', '\u{0}']), ('\u{441}', ['\u{421}', '\u{0}', '\u{0}']), - ('\u{442}', ['\u{422}', '\u{0}', '\u{0}']), ('\u{443}', ['\u{423}', '\u{0}', '\u{0}']), - ('\u{444}', ['\u{424}', '\u{0}', '\u{0}']), ('\u{445}', ['\u{425}', '\u{0}', '\u{0}']), - ('\u{446}', ['\u{426}', '\u{0}', '\u{0}']), ('\u{447}', ['\u{427}', '\u{0}', '\u{0}']), - ('\u{448}', ['\u{428}', '\u{0}', '\u{0}']), ('\u{449}', ['\u{429}', '\u{0}', '\u{0}']), - ('\u{44a}', ['\u{42a}', '\u{0}', '\u{0}']), ('\u{44b}', ['\u{42b}', '\u{0}', '\u{0}']), - ('\u{44c}', ['\u{42c}', '\u{0}', '\u{0}']), ('\u{44d}', ['\u{42d}', '\u{0}', '\u{0}']), - ('\u{44e}', ['\u{42e}', '\u{0}', '\u{0}']), ('\u{44f}', ['\u{42f}', '\u{0}', '\u{0}']), - ('\u{450}', ['\u{400}', '\u{0}', '\u{0}']), ('\u{451}', ['\u{401}', '\u{0}', '\u{0}']), - ('\u{452}', ['\u{402}', '\u{0}', '\u{0}']), ('\u{453}', ['\u{403}', '\u{0}', '\u{0}']), - ('\u{454}', ['\u{404}', '\u{0}', '\u{0}']), ('\u{455}', ['\u{405}', '\u{0}', '\u{0}']), - ('\u{456}', ['\u{406}', '\u{0}', '\u{0}']), ('\u{457}', ['\u{407}', '\u{0}', '\u{0}']), - ('\u{458}', ['\u{408}', '\u{0}', '\u{0}']), ('\u{459}', ['\u{409}', '\u{0}', '\u{0}']), - ('\u{45a}', ['\u{40a}', '\u{0}', '\u{0}']), ('\u{45b}', ['\u{40b}', '\u{0}', '\u{0}']), - ('\u{45c}', ['\u{40c}', '\u{0}', '\u{0}']), ('\u{45d}', ['\u{40d}', '\u{0}', '\u{0}']), - ('\u{45e}', ['\u{40e}', '\u{0}', '\u{0}']), ('\u{45f}', ['\u{40f}', '\u{0}', '\u{0}']), - ('\u{461}', ['\u{460}', '\u{0}', '\u{0}']), ('\u{463}', ['\u{462}', '\u{0}', '\u{0}']), - ('\u{465}', ['\u{464}', '\u{0}', '\u{0}']), ('\u{467}', ['\u{466}', '\u{0}', '\u{0}']), - ('\u{469}', ['\u{468}', '\u{0}', '\u{0}']), ('\u{46b}', ['\u{46a}', '\u{0}', '\u{0}']), - ('\u{46d}', ['\u{46c}', '\u{0}', '\u{0}']), ('\u{46f}', ['\u{46e}', '\u{0}', '\u{0}']), - ('\u{471}', ['\u{470}', '\u{0}', '\u{0}']), ('\u{473}', ['\u{472}', '\u{0}', '\u{0}']), - ('\u{475}', ['\u{474}', '\u{0}', '\u{0}']), ('\u{477}', ['\u{476}', '\u{0}', '\u{0}']), - ('\u{479}', ['\u{478}', '\u{0}', '\u{0}']), ('\u{47b}', ['\u{47a}', '\u{0}', '\u{0}']), - ('\u{47d}', ['\u{47c}', '\u{0}', '\u{0}']), ('\u{47f}', ['\u{47e}', '\u{0}', '\u{0}']), - ('\u{481}', ['\u{480}', '\u{0}', '\u{0}']), ('\u{48b}', ['\u{48a}', '\u{0}', '\u{0}']), - ('\u{48d}', ['\u{48c}', '\u{0}', '\u{0}']), ('\u{48f}', ['\u{48e}', '\u{0}', '\u{0}']), - ('\u{491}', ['\u{490}', '\u{0}', '\u{0}']), ('\u{493}', ['\u{492}', '\u{0}', '\u{0}']), - ('\u{495}', ['\u{494}', '\u{0}', '\u{0}']), ('\u{497}', ['\u{496}', '\u{0}', '\u{0}']), - ('\u{499}', ['\u{498}', '\u{0}', '\u{0}']), ('\u{49b}', ['\u{49a}', '\u{0}', '\u{0}']), - ('\u{49d}', ['\u{49c}', '\u{0}', '\u{0}']), ('\u{49f}', ['\u{49e}', '\u{0}', '\u{0}']), - ('\u{4a1}', ['\u{4a0}', '\u{0}', '\u{0}']), ('\u{4a3}', ['\u{4a2}', '\u{0}', '\u{0}']), - ('\u{4a5}', ['\u{4a4}', '\u{0}', '\u{0}']), ('\u{4a7}', ['\u{4a6}', '\u{0}', '\u{0}']), - ('\u{4a9}', ['\u{4a8}', '\u{0}', '\u{0}']), ('\u{4ab}', ['\u{4aa}', '\u{0}', '\u{0}']), - ('\u{4ad}', ['\u{4ac}', '\u{0}', '\u{0}']), ('\u{4af}', ['\u{4ae}', '\u{0}', '\u{0}']), - ('\u{4b1}', ['\u{4b0}', '\u{0}', '\u{0}']), ('\u{4b3}', ['\u{4b2}', '\u{0}', '\u{0}']), - ('\u{4b5}', ['\u{4b4}', '\u{0}', '\u{0}']), ('\u{4b7}', ['\u{4b6}', '\u{0}', '\u{0}']), - ('\u{4b9}', ['\u{4b8}', '\u{0}', '\u{0}']), ('\u{4bb}', ['\u{4ba}', '\u{0}', '\u{0}']), - ('\u{4bd}', ['\u{4bc}', '\u{0}', '\u{0}']), ('\u{4bf}', ['\u{4be}', '\u{0}', '\u{0}']), - ('\u{4c2}', ['\u{4c1}', '\u{0}', '\u{0}']), ('\u{4c4}', ['\u{4c3}', '\u{0}', '\u{0}']), - ('\u{4c6}', ['\u{4c5}', '\u{0}', '\u{0}']), ('\u{4c8}', ['\u{4c7}', '\u{0}', '\u{0}']), - ('\u{4ca}', ['\u{4c9}', '\u{0}', '\u{0}']), ('\u{4cc}', ['\u{4cb}', '\u{0}', '\u{0}']), - ('\u{4ce}', ['\u{4cd}', '\u{0}', '\u{0}']), ('\u{4cf}', ['\u{4c0}', '\u{0}', '\u{0}']), - ('\u{4d1}', ['\u{4d0}', '\u{0}', '\u{0}']), ('\u{4d3}', ['\u{4d2}', '\u{0}', '\u{0}']), - ('\u{4d5}', ['\u{4d4}', '\u{0}', '\u{0}']), ('\u{4d7}', ['\u{4d6}', '\u{0}', '\u{0}']), - ('\u{4d9}', ['\u{4d8}', '\u{0}', '\u{0}']), ('\u{4db}', ['\u{4da}', '\u{0}', '\u{0}']), - ('\u{4dd}', ['\u{4dc}', '\u{0}', '\u{0}']), ('\u{4df}', ['\u{4de}', '\u{0}', '\u{0}']), - ('\u{4e1}', ['\u{4e0}', '\u{0}', '\u{0}']), ('\u{4e3}', ['\u{4e2}', '\u{0}', '\u{0}']), - ('\u{4e5}', ['\u{4e4}', '\u{0}', '\u{0}']), ('\u{4e7}', ['\u{4e6}', '\u{0}', '\u{0}']), - ('\u{4e9}', ['\u{4e8}', '\u{0}', '\u{0}']), ('\u{4eb}', ['\u{4ea}', '\u{0}', '\u{0}']), - ('\u{4ed}', ['\u{4ec}', '\u{0}', '\u{0}']), ('\u{4ef}', ['\u{4ee}', '\u{0}', '\u{0}']), - ('\u{4f1}', ['\u{4f0}', '\u{0}', '\u{0}']), ('\u{4f3}', ['\u{4f2}', '\u{0}', '\u{0}']), - ('\u{4f5}', ['\u{4f4}', '\u{0}', '\u{0}']), ('\u{4f7}', ['\u{4f6}', '\u{0}', '\u{0}']), - ('\u{4f9}', ['\u{4f8}', '\u{0}', '\u{0}']), ('\u{4fb}', ['\u{4fa}', '\u{0}', '\u{0}']), - ('\u{4fd}', ['\u{4fc}', '\u{0}', '\u{0}']), ('\u{4ff}', ['\u{4fe}', '\u{0}', '\u{0}']), - ('\u{501}', ['\u{500}', '\u{0}', '\u{0}']), ('\u{503}', ['\u{502}', '\u{0}', '\u{0}']), - ('\u{505}', ['\u{504}', '\u{0}', '\u{0}']), ('\u{507}', ['\u{506}', '\u{0}', '\u{0}']), - ('\u{509}', ['\u{508}', '\u{0}', '\u{0}']), ('\u{50b}', ['\u{50a}', '\u{0}', '\u{0}']), - ('\u{50d}', ['\u{50c}', '\u{0}', '\u{0}']), ('\u{50f}', ['\u{50e}', '\u{0}', '\u{0}']), - ('\u{511}', ['\u{510}', '\u{0}', '\u{0}']), ('\u{513}', ['\u{512}', '\u{0}', '\u{0}']), - ('\u{515}', ['\u{514}', '\u{0}', '\u{0}']), ('\u{517}', ['\u{516}', '\u{0}', '\u{0}']), - ('\u{519}', ['\u{518}', '\u{0}', '\u{0}']), ('\u{51b}', ['\u{51a}', '\u{0}', '\u{0}']), - ('\u{51d}', ['\u{51c}', '\u{0}', '\u{0}']), ('\u{51f}', ['\u{51e}', '\u{0}', '\u{0}']), - ('\u{521}', ['\u{520}', '\u{0}', '\u{0}']), ('\u{523}', ['\u{522}', '\u{0}', '\u{0}']), - ('\u{525}', ['\u{524}', '\u{0}', '\u{0}']), ('\u{527}', ['\u{526}', '\u{0}', '\u{0}']), - ('\u{529}', ['\u{528}', '\u{0}', '\u{0}']), ('\u{52b}', ['\u{52a}', '\u{0}', '\u{0}']), - ('\u{52d}', ['\u{52c}', '\u{0}', '\u{0}']), ('\u{52f}', ['\u{52e}', '\u{0}', '\u{0}']), - ('\u{561}', ['\u{531}', '\u{0}', '\u{0}']), ('\u{562}', ['\u{532}', '\u{0}', '\u{0}']), - ('\u{563}', ['\u{533}', '\u{0}', '\u{0}']), ('\u{564}', ['\u{534}', '\u{0}', '\u{0}']), - ('\u{565}', ['\u{535}', '\u{0}', '\u{0}']), ('\u{566}', ['\u{536}', '\u{0}', '\u{0}']), - ('\u{567}', ['\u{537}', '\u{0}', '\u{0}']), ('\u{568}', ['\u{538}', '\u{0}', '\u{0}']), - ('\u{569}', ['\u{539}', '\u{0}', '\u{0}']), ('\u{56a}', ['\u{53a}', '\u{0}', '\u{0}']), - ('\u{56b}', ['\u{53b}', '\u{0}', '\u{0}']), ('\u{56c}', ['\u{53c}', '\u{0}', '\u{0}']), - ('\u{56d}', ['\u{53d}', '\u{0}', '\u{0}']), ('\u{56e}', ['\u{53e}', '\u{0}', '\u{0}']), - ('\u{56f}', ['\u{53f}', '\u{0}', '\u{0}']), ('\u{570}', ['\u{540}', '\u{0}', '\u{0}']), - ('\u{571}', ['\u{541}', '\u{0}', '\u{0}']), ('\u{572}', ['\u{542}', '\u{0}', '\u{0}']), - ('\u{573}', ['\u{543}', '\u{0}', '\u{0}']), ('\u{574}', ['\u{544}', '\u{0}', '\u{0}']), - ('\u{575}', ['\u{545}', '\u{0}', '\u{0}']), ('\u{576}', ['\u{546}', '\u{0}', '\u{0}']), - ('\u{577}', ['\u{547}', '\u{0}', '\u{0}']), ('\u{578}', ['\u{548}', '\u{0}', '\u{0}']), - ('\u{579}', ['\u{549}', '\u{0}', '\u{0}']), ('\u{57a}', ['\u{54a}', '\u{0}', '\u{0}']), - ('\u{57b}', ['\u{54b}', '\u{0}', '\u{0}']), ('\u{57c}', ['\u{54c}', '\u{0}', '\u{0}']), - ('\u{57d}', ['\u{54d}', '\u{0}', '\u{0}']), ('\u{57e}', ['\u{54e}', '\u{0}', '\u{0}']), - ('\u{57f}', ['\u{54f}', '\u{0}', '\u{0}']), ('\u{580}', ['\u{550}', '\u{0}', '\u{0}']), - ('\u{581}', ['\u{551}', '\u{0}', '\u{0}']), ('\u{582}', ['\u{552}', '\u{0}', '\u{0}']), - ('\u{583}', ['\u{553}', '\u{0}', '\u{0}']), ('\u{584}', ['\u{554}', '\u{0}', '\u{0}']), - ('\u{585}', ['\u{555}', '\u{0}', '\u{0}']), ('\u{586}', ['\u{556}', '\u{0}', '\u{0}']), - ('\u{587}', ['\u{535}', '\u{552}', '\u{0}']), ('\u{10d0}', ['\u{1c90}', '\u{0}', '\u{0}']), - ('\u{10d1}', ['\u{1c91}', '\u{0}', '\u{0}']), ('\u{10d2}', ['\u{1c92}', '\u{0}', '\u{0}']), - ('\u{10d3}', ['\u{1c93}', '\u{0}', '\u{0}']), ('\u{10d4}', ['\u{1c94}', '\u{0}', '\u{0}']), - ('\u{10d5}', ['\u{1c95}', '\u{0}', '\u{0}']), ('\u{10d6}', ['\u{1c96}', '\u{0}', '\u{0}']), - ('\u{10d7}', ['\u{1c97}', '\u{0}', '\u{0}']), ('\u{10d8}', ['\u{1c98}', '\u{0}', '\u{0}']), - ('\u{10d9}', ['\u{1c99}', '\u{0}', '\u{0}']), ('\u{10da}', ['\u{1c9a}', '\u{0}', '\u{0}']), - ('\u{10db}', ['\u{1c9b}', '\u{0}', '\u{0}']), ('\u{10dc}', ['\u{1c9c}', '\u{0}', '\u{0}']), - ('\u{10dd}', ['\u{1c9d}', '\u{0}', '\u{0}']), ('\u{10de}', ['\u{1c9e}', '\u{0}', '\u{0}']), - ('\u{10df}', ['\u{1c9f}', '\u{0}', '\u{0}']), ('\u{10e0}', ['\u{1ca0}', '\u{0}', '\u{0}']), - ('\u{10e1}', ['\u{1ca1}', '\u{0}', '\u{0}']), ('\u{10e2}', ['\u{1ca2}', '\u{0}', '\u{0}']), - ('\u{10e3}', ['\u{1ca3}', '\u{0}', '\u{0}']), ('\u{10e4}', ['\u{1ca4}', '\u{0}', '\u{0}']), - ('\u{10e5}', ['\u{1ca5}', '\u{0}', '\u{0}']), ('\u{10e6}', ['\u{1ca6}', '\u{0}', '\u{0}']), - ('\u{10e7}', ['\u{1ca7}', '\u{0}', '\u{0}']), ('\u{10e8}', ['\u{1ca8}', '\u{0}', '\u{0}']), - ('\u{10e9}', ['\u{1ca9}', '\u{0}', '\u{0}']), ('\u{10ea}', ['\u{1caa}', '\u{0}', '\u{0}']), - ('\u{10eb}', ['\u{1cab}', '\u{0}', '\u{0}']), ('\u{10ec}', ['\u{1cac}', '\u{0}', '\u{0}']), - ('\u{10ed}', ['\u{1cad}', '\u{0}', '\u{0}']), ('\u{10ee}', ['\u{1cae}', '\u{0}', '\u{0}']), - ('\u{10ef}', ['\u{1caf}', '\u{0}', '\u{0}']), ('\u{10f0}', ['\u{1cb0}', '\u{0}', '\u{0}']), - ('\u{10f1}', ['\u{1cb1}', '\u{0}', '\u{0}']), ('\u{10f2}', ['\u{1cb2}', '\u{0}', '\u{0}']), - ('\u{10f3}', ['\u{1cb3}', '\u{0}', '\u{0}']), ('\u{10f4}', ['\u{1cb4}', '\u{0}', '\u{0}']), - ('\u{10f5}', ['\u{1cb5}', '\u{0}', '\u{0}']), ('\u{10f6}', ['\u{1cb6}', '\u{0}', '\u{0}']), - ('\u{10f7}', ['\u{1cb7}', '\u{0}', '\u{0}']), ('\u{10f8}', ['\u{1cb8}', '\u{0}', '\u{0}']), - ('\u{10f9}', ['\u{1cb9}', '\u{0}', '\u{0}']), ('\u{10fa}', ['\u{1cba}', '\u{0}', '\u{0}']), - ('\u{10fd}', ['\u{1cbd}', '\u{0}', '\u{0}']), ('\u{10fe}', ['\u{1cbe}', '\u{0}', '\u{0}']), - ('\u{10ff}', ['\u{1cbf}', '\u{0}', '\u{0}']), ('\u{13f8}', ['\u{13f0}', '\u{0}', '\u{0}']), - ('\u{13f9}', ['\u{13f1}', '\u{0}', '\u{0}']), ('\u{13fa}', ['\u{13f2}', '\u{0}', '\u{0}']), - ('\u{13fb}', ['\u{13f3}', '\u{0}', '\u{0}']), ('\u{13fc}', ['\u{13f4}', '\u{0}', '\u{0}']), - ('\u{13fd}', ['\u{13f5}', '\u{0}', '\u{0}']), ('\u{1c80}', ['\u{412}', '\u{0}', '\u{0}']), - ('\u{1c81}', ['\u{414}', '\u{0}', '\u{0}']), ('\u{1c82}', ['\u{41e}', '\u{0}', '\u{0}']), - ('\u{1c83}', ['\u{421}', '\u{0}', '\u{0}']), ('\u{1c84}', ['\u{422}', '\u{0}', '\u{0}']), - ('\u{1c85}', ['\u{422}', '\u{0}', '\u{0}']), ('\u{1c86}', ['\u{42a}', '\u{0}', '\u{0}']), - ('\u{1c87}', ['\u{462}', '\u{0}', '\u{0}']), ('\u{1c88}', ['\u{a64a}', '\u{0}', '\u{0}']), - ('\u{1d79}', ['\u{a77d}', '\u{0}', '\u{0}']), ('\u{1d7d}', ['\u{2c63}', '\u{0}', '\u{0}']), - ('\u{1d8e}', ['\u{a7c6}', '\u{0}', '\u{0}']), ('\u{1e01}', ['\u{1e00}', '\u{0}', '\u{0}']), - ('\u{1e03}', ['\u{1e02}', '\u{0}', '\u{0}']), ('\u{1e05}', ['\u{1e04}', '\u{0}', '\u{0}']), - ('\u{1e07}', ['\u{1e06}', '\u{0}', '\u{0}']), ('\u{1e09}', ['\u{1e08}', '\u{0}', '\u{0}']), - ('\u{1e0b}', ['\u{1e0a}', '\u{0}', '\u{0}']), ('\u{1e0d}', ['\u{1e0c}', '\u{0}', '\u{0}']), - ('\u{1e0f}', ['\u{1e0e}', '\u{0}', '\u{0}']), ('\u{1e11}', ['\u{1e10}', '\u{0}', '\u{0}']), - ('\u{1e13}', ['\u{1e12}', '\u{0}', '\u{0}']), ('\u{1e15}', ['\u{1e14}', '\u{0}', '\u{0}']), - ('\u{1e17}', ['\u{1e16}', '\u{0}', '\u{0}']), ('\u{1e19}', ['\u{1e18}', '\u{0}', '\u{0}']), - ('\u{1e1b}', ['\u{1e1a}', '\u{0}', '\u{0}']), ('\u{1e1d}', ['\u{1e1c}', '\u{0}', '\u{0}']), - ('\u{1e1f}', ['\u{1e1e}', '\u{0}', '\u{0}']), ('\u{1e21}', ['\u{1e20}', '\u{0}', '\u{0}']), - ('\u{1e23}', ['\u{1e22}', '\u{0}', '\u{0}']), ('\u{1e25}', ['\u{1e24}', '\u{0}', '\u{0}']), - ('\u{1e27}', ['\u{1e26}', '\u{0}', '\u{0}']), ('\u{1e29}', ['\u{1e28}', '\u{0}', '\u{0}']), - ('\u{1e2b}', ['\u{1e2a}', '\u{0}', '\u{0}']), ('\u{1e2d}', ['\u{1e2c}', '\u{0}', '\u{0}']), - ('\u{1e2f}', ['\u{1e2e}', '\u{0}', '\u{0}']), ('\u{1e31}', ['\u{1e30}', '\u{0}', '\u{0}']), - ('\u{1e33}', ['\u{1e32}', '\u{0}', '\u{0}']), ('\u{1e35}', ['\u{1e34}', '\u{0}', '\u{0}']), - ('\u{1e37}', ['\u{1e36}', '\u{0}', '\u{0}']), ('\u{1e39}', ['\u{1e38}', '\u{0}', '\u{0}']), - ('\u{1e3b}', ['\u{1e3a}', '\u{0}', '\u{0}']), ('\u{1e3d}', ['\u{1e3c}', '\u{0}', '\u{0}']), - ('\u{1e3f}', ['\u{1e3e}', '\u{0}', '\u{0}']), ('\u{1e41}', ['\u{1e40}', '\u{0}', '\u{0}']), - ('\u{1e43}', ['\u{1e42}', '\u{0}', '\u{0}']), ('\u{1e45}', ['\u{1e44}', '\u{0}', '\u{0}']), - ('\u{1e47}', ['\u{1e46}', '\u{0}', '\u{0}']), ('\u{1e49}', ['\u{1e48}', '\u{0}', '\u{0}']), - ('\u{1e4b}', ['\u{1e4a}', '\u{0}', '\u{0}']), ('\u{1e4d}', ['\u{1e4c}', '\u{0}', '\u{0}']), - ('\u{1e4f}', ['\u{1e4e}', '\u{0}', '\u{0}']), ('\u{1e51}', ['\u{1e50}', '\u{0}', '\u{0}']), - ('\u{1e53}', ['\u{1e52}', '\u{0}', '\u{0}']), ('\u{1e55}', ['\u{1e54}', '\u{0}', '\u{0}']), - ('\u{1e57}', ['\u{1e56}', '\u{0}', '\u{0}']), ('\u{1e59}', ['\u{1e58}', '\u{0}', '\u{0}']), - ('\u{1e5b}', ['\u{1e5a}', '\u{0}', '\u{0}']), ('\u{1e5d}', ['\u{1e5c}', '\u{0}', '\u{0}']), - ('\u{1e5f}', ['\u{1e5e}', '\u{0}', '\u{0}']), ('\u{1e61}', ['\u{1e60}', '\u{0}', '\u{0}']), - ('\u{1e63}', ['\u{1e62}', '\u{0}', '\u{0}']), ('\u{1e65}', ['\u{1e64}', '\u{0}', '\u{0}']), - ('\u{1e67}', ['\u{1e66}', '\u{0}', '\u{0}']), ('\u{1e69}', ['\u{1e68}', '\u{0}', '\u{0}']), - ('\u{1e6b}', ['\u{1e6a}', '\u{0}', '\u{0}']), ('\u{1e6d}', ['\u{1e6c}', '\u{0}', '\u{0}']), - ('\u{1e6f}', ['\u{1e6e}', '\u{0}', '\u{0}']), ('\u{1e71}', ['\u{1e70}', '\u{0}', '\u{0}']), - ('\u{1e73}', ['\u{1e72}', '\u{0}', '\u{0}']), ('\u{1e75}', ['\u{1e74}', '\u{0}', '\u{0}']), - ('\u{1e77}', ['\u{1e76}', '\u{0}', '\u{0}']), ('\u{1e79}', ['\u{1e78}', '\u{0}', '\u{0}']), - ('\u{1e7b}', ['\u{1e7a}', '\u{0}', '\u{0}']), ('\u{1e7d}', ['\u{1e7c}', '\u{0}', '\u{0}']), - ('\u{1e7f}', ['\u{1e7e}', '\u{0}', '\u{0}']), ('\u{1e81}', ['\u{1e80}', '\u{0}', '\u{0}']), - ('\u{1e83}', ['\u{1e82}', '\u{0}', '\u{0}']), ('\u{1e85}', ['\u{1e84}', '\u{0}', '\u{0}']), - ('\u{1e87}', ['\u{1e86}', '\u{0}', '\u{0}']), ('\u{1e89}', ['\u{1e88}', '\u{0}', '\u{0}']), - ('\u{1e8b}', ['\u{1e8a}', '\u{0}', '\u{0}']), ('\u{1e8d}', ['\u{1e8c}', '\u{0}', '\u{0}']), - ('\u{1e8f}', ['\u{1e8e}', '\u{0}', '\u{0}']), ('\u{1e91}', ['\u{1e90}', '\u{0}', '\u{0}']), - ('\u{1e93}', ['\u{1e92}', '\u{0}', '\u{0}']), ('\u{1e95}', ['\u{1e94}', '\u{0}', '\u{0}']), - ('\u{1e96}', ['H', '\u{331}', '\u{0}']), ('\u{1e97}', ['T', '\u{308}', '\u{0}']), - ('\u{1e98}', ['W', '\u{30a}', '\u{0}']), ('\u{1e99}', ['Y', '\u{30a}', '\u{0}']), - ('\u{1e9a}', ['A', '\u{2be}', '\u{0}']), ('\u{1e9b}', ['\u{1e60}', '\u{0}', '\u{0}']), - ('\u{1ea1}', ['\u{1ea0}', '\u{0}', '\u{0}']), ('\u{1ea3}', ['\u{1ea2}', '\u{0}', '\u{0}']), - ('\u{1ea5}', ['\u{1ea4}', '\u{0}', '\u{0}']), ('\u{1ea7}', ['\u{1ea6}', '\u{0}', '\u{0}']), - ('\u{1ea9}', ['\u{1ea8}', '\u{0}', '\u{0}']), ('\u{1eab}', ['\u{1eaa}', '\u{0}', '\u{0}']), - ('\u{1ead}', ['\u{1eac}', '\u{0}', '\u{0}']), ('\u{1eaf}', ['\u{1eae}', '\u{0}', '\u{0}']), - ('\u{1eb1}', ['\u{1eb0}', '\u{0}', '\u{0}']), ('\u{1eb3}', ['\u{1eb2}', '\u{0}', '\u{0}']), - ('\u{1eb5}', ['\u{1eb4}', '\u{0}', '\u{0}']), ('\u{1eb7}', ['\u{1eb6}', '\u{0}', '\u{0}']), - ('\u{1eb9}', ['\u{1eb8}', '\u{0}', '\u{0}']), ('\u{1ebb}', ['\u{1eba}', '\u{0}', '\u{0}']), - ('\u{1ebd}', ['\u{1ebc}', '\u{0}', '\u{0}']), ('\u{1ebf}', ['\u{1ebe}', '\u{0}', '\u{0}']), - ('\u{1ec1}', ['\u{1ec0}', '\u{0}', '\u{0}']), ('\u{1ec3}', ['\u{1ec2}', '\u{0}', '\u{0}']), - ('\u{1ec5}', ['\u{1ec4}', '\u{0}', '\u{0}']), ('\u{1ec7}', ['\u{1ec6}', '\u{0}', '\u{0}']), - ('\u{1ec9}', ['\u{1ec8}', '\u{0}', '\u{0}']), ('\u{1ecb}', ['\u{1eca}', '\u{0}', '\u{0}']), - ('\u{1ecd}', ['\u{1ecc}', '\u{0}', '\u{0}']), ('\u{1ecf}', ['\u{1ece}', '\u{0}', '\u{0}']), - ('\u{1ed1}', ['\u{1ed0}', '\u{0}', '\u{0}']), ('\u{1ed3}', ['\u{1ed2}', '\u{0}', '\u{0}']), - ('\u{1ed5}', ['\u{1ed4}', '\u{0}', '\u{0}']), ('\u{1ed7}', ['\u{1ed6}', '\u{0}', '\u{0}']), - ('\u{1ed9}', ['\u{1ed8}', '\u{0}', '\u{0}']), ('\u{1edb}', ['\u{1eda}', '\u{0}', '\u{0}']), - ('\u{1edd}', ['\u{1edc}', '\u{0}', '\u{0}']), ('\u{1edf}', ['\u{1ede}', '\u{0}', '\u{0}']), - ('\u{1ee1}', ['\u{1ee0}', '\u{0}', '\u{0}']), ('\u{1ee3}', ['\u{1ee2}', '\u{0}', '\u{0}']), - ('\u{1ee5}', ['\u{1ee4}', '\u{0}', '\u{0}']), ('\u{1ee7}', ['\u{1ee6}', '\u{0}', '\u{0}']), - ('\u{1ee9}', ['\u{1ee8}', '\u{0}', '\u{0}']), ('\u{1eeb}', ['\u{1eea}', '\u{0}', '\u{0}']), - ('\u{1eed}', ['\u{1eec}', '\u{0}', '\u{0}']), ('\u{1eef}', ['\u{1eee}', '\u{0}', '\u{0}']), - ('\u{1ef1}', ['\u{1ef0}', '\u{0}', '\u{0}']), ('\u{1ef3}', ['\u{1ef2}', '\u{0}', '\u{0}']), - ('\u{1ef5}', ['\u{1ef4}', '\u{0}', '\u{0}']), ('\u{1ef7}', ['\u{1ef6}', '\u{0}', '\u{0}']), - ('\u{1ef9}', ['\u{1ef8}', '\u{0}', '\u{0}']), ('\u{1efb}', ['\u{1efa}', '\u{0}', '\u{0}']), - ('\u{1efd}', ['\u{1efc}', '\u{0}', '\u{0}']), ('\u{1eff}', ['\u{1efe}', '\u{0}', '\u{0}']), - ('\u{1f00}', ['\u{1f08}', '\u{0}', '\u{0}']), ('\u{1f01}', ['\u{1f09}', '\u{0}', '\u{0}']), - ('\u{1f02}', ['\u{1f0a}', '\u{0}', '\u{0}']), ('\u{1f03}', ['\u{1f0b}', '\u{0}', '\u{0}']), - ('\u{1f04}', ['\u{1f0c}', '\u{0}', '\u{0}']), ('\u{1f05}', ['\u{1f0d}', '\u{0}', '\u{0}']), - ('\u{1f06}', ['\u{1f0e}', '\u{0}', '\u{0}']), ('\u{1f07}', ['\u{1f0f}', '\u{0}', '\u{0}']), - ('\u{1f10}', ['\u{1f18}', '\u{0}', '\u{0}']), ('\u{1f11}', ['\u{1f19}', '\u{0}', '\u{0}']), - ('\u{1f12}', ['\u{1f1a}', '\u{0}', '\u{0}']), ('\u{1f13}', ['\u{1f1b}', '\u{0}', '\u{0}']), - ('\u{1f14}', ['\u{1f1c}', '\u{0}', '\u{0}']), ('\u{1f15}', ['\u{1f1d}', '\u{0}', '\u{0}']), - ('\u{1f20}', ['\u{1f28}', '\u{0}', '\u{0}']), ('\u{1f21}', ['\u{1f29}', '\u{0}', '\u{0}']), - ('\u{1f22}', ['\u{1f2a}', '\u{0}', '\u{0}']), ('\u{1f23}', ['\u{1f2b}', '\u{0}', '\u{0}']), - ('\u{1f24}', ['\u{1f2c}', '\u{0}', '\u{0}']), ('\u{1f25}', ['\u{1f2d}', '\u{0}', '\u{0}']), - ('\u{1f26}', ['\u{1f2e}', '\u{0}', '\u{0}']), ('\u{1f27}', ['\u{1f2f}', '\u{0}', '\u{0}']), - ('\u{1f30}', ['\u{1f38}', '\u{0}', '\u{0}']), ('\u{1f31}', ['\u{1f39}', '\u{0}', '\u{0}']), - ('\u{1f32}', ['\u{1f3a}', '\u{0}', '\u{0}']), ('\u{1f33}', ['\u{1f3b}', '\u{0}', '\u{0}']), - ('\u{1f34}', ['\u{1f3c}', '\u{0}', '\u{0}']), ('\u{1f35}', ['\u{1f3d}', '\u{0}', '\u{0}']), - ('\u{1f36}', ['\u{1f3e}', '\u{0}', '\u{0}']), ('\u{1f37}', ['\u{1f3f}', '\u{0}', '\u{0}']), - ('\u{1f40}', ['\u{1f48}', '\u{0}', '\u{0}']), ('\u{1f41}', ['\u{1f49}', '\u{0}', '\u{0}']), - ('\u{1f42}', ['\u{1f4a}', '\u{0}', '\u{0}']), ('\u{1f43}', ['\u{1f4b}', '\u{0}', '\u{0}']), - ('\u{1f44}', ['\u{1f4c}', '\u{0}', '\u{0}']), ('\u{1f45}', ['\u{1f4d}', '\u{0}', '\u{0}']), - ('\u{1f50}', ['\u{3a5}', '\u{313}', '\u{0}']), ('\u{1f51}', ['\u{1f59}', '\u{0}', '\u{0}']), - ('\u{1f52}', ['\u{3a5}', '\u{313}', '\u{300}']), - ('\u{1f53}', ['\u{1f5b}', '\u{0}', '\u{0}']), - ('\u{1f54}', ['\u{3a5}', '\u{313}', '\u{301}']), - ('\u{1f55}', ['\u{1f5d}', '\u{0}', '\u{0}']), - ('\u{1f56}', ['\u{3a5}', '\u{313}', '\u{342}']), - ('\u{1f57}', ['\u{1f5f}', '\u{0}', '\u{0}']), ('\u{1f60}', ['\u{1f68}', '\u{0}', '\u{0}']), - ('\u{1f61}', ['\u{1f69}', '\u{0}', '\u{0}']), ('\u{1f62}', ['\u{1f6a}', '\u{0}', '\u{0}']), - ('\u{1f63}', ['\u{1f6b}', '\u{0}', '\u{0}']), ('\u{1f64}', ['\u{1f6c}', '\u{0}', '\u{0}']), - ('\u{1f65}', ['\u{1f6d}', '\u{0}', '\u{0}']), ('\u{1f66}', ['\u{1f6e}', '\u{0}', '\u{0}']), - ('\u{1f67}', ['\u{1f6f}', '\u{0}', '\u{0}']), ('\u{1f70}', ['\u{1fba}', '\u{0}', '\u{0}']), - ('\u{1f71}', ['\u{1fbb}', '\u{0}', '\u{0}']), ('\u{1f72}', ['\u{1fc8}', '\u{0}', '\u{0}']), - ('\u{1f73}', ['\u{1fc9}', '\u{0}', '\u{0}']), ('\u{1f74}', ['\u{1fca}', '\u{0}', '\u{0}']), - ('\u{1f75}', ['\u{1fcb}', '\u{0}', '\u{0}']), ('\u{1f76}', ['\u{1fda}', '\u{0}', '\u{0}']), - ('\u{1f77}', ['\u{1fdb}', '\u{0}', '\u{0}']), ('\u{1f78}', ['\u{1ff8}', '\u{0}', '\u{0}']), - ('\u{1f79}', ['\u{1ff9}', '\u{0}', '\u{0}']), ('\u{1f7a}', ['\u{1fea}', '\u{0}', '\u{0}']), - ('\u{1f7b}', ['\u{1feb}', '\u{0}', '\u{0}']), ('\u{1f7c}', ['\u{1ffa}', '\u{0}', '\u{0}']), - ('\u{1f7d}', ['\u{1ffb}', '\u{0}', '\u{0}']), - ('\u{1f80}', ['\u{1f08}', '\u{399}', '\u{0}']), - ('\u{1f81}', ['\u{1f09}', '\u{399}', '\u{0}']), - ('\u{1f82}', ['\u{1f0a}', '\u{399}', '\u{0}']), - ('\u{1f83}', ['\u{1f0b}', '\u{399}', '\u{0}']), - ('\u{1f84}', ['\u{1f0c}', '\u{399}', '\u{0}']), - ('\u{1f85}', ['\u{1f0d}', '\u{399}', '\u{0}']), - ('\u{1f86}', ['\u{1f0e}', '\u{399}', '\u{0}']), - ('\u{1f87}', ['\u{1f0f}', '\u{399}', '\u{0}']), - ('\u{1f88}', ['\u{1f08}', '\u{399}', '\u{0}']), - ('\u{1f89}', ['\u{1f09}', '\u{399}', '\u{0}']), - ('\u{1f8a}', ['\u{1f0a}', '\u{399}', '\u{0}']), - ('\u{1f8b}', ['\u{1f0b}', '\u{399}', '\u{0}']), - ('\u{1f8c}', ['\u{1f0c}', '\u{399}', '\u{0}']), - ('\u{1f8d}', ['\u{1f0d}', '\u{399}', '\u{0}']), - ('\u{1f8e}', ['\u{1f0e}', '\u{399}', '\u{0}']), - ('\u{1f8f}', ['\u{1f0f}', '\u{399}', '\u{0}']), - ('\u{1f90}', ['\u{1f28}', '\u{399}', '\u{0}']), - ('\u{1f91}', ['\u{1f29}', '\u{399}', '\u{0}']), - ('\u{1f92}', ['\u{1f2a}', '\u{399}', '\u{0}']), - ('\u{1f93}', ['\u{1f2b}', '\u{399}', '\u{0}']), - ('\u{1f94}', ['\u{1f2c}', '\u{399}', '\u{0}']), - ('\u{1f95}', ['\u{1f2d}', '\u{399}', '\u{0}']), - ('\u{1f96}', ['\u{1f2e}', '\u{399}', '\u{0}']), - ('\u{1f97}', ['\u{1f2f}', '\u{399}', '\u{0}']), - ('\u{1f98}', ['\u{1f28}', '\u{399}', '\u{0}']), - ('\u{1f99}', ['\u{1f29}', '\u{399}', '\u{0}']), - ('\u{1f9a}', ['\u{1f2a}', '\u{399}', '\u{0}']), - ('\u{1f9b}', ['\u{1f2b}', '\u{399}', '\u{0}']), - ('\u{1f9c}', ['\u{1f2c}', '\u{399}', '\u{0}']), - ('\u{1f9d}', ['\u{1f2d}', '\u{399}', '\u{0}']), - ('\u{1f9e}', ['\u{1f2e}', '\u{399}', '\u{0}']), - ('\u{1f9f}', ['\u{1f2f}', '\u{399}', '\u{0}']), - ('\u{1fa0}', ['\u{1f68}', '\u{399}', '\u{0}']), - ('\u{1fa1}', ['\u{1f69}', '\u{399}', '\u{0}']), - ('\u{1fa2}', ['\u{1f6a}', '\u{399}', '\u{0}']), - ('\u{1fa3}', ['\u{1f6b}', '\u{399}', '\u{0}']), - ('\u{1fa4}', ['\u{1f6c}', '\u{399}', '\u{0}']), - ('\u{1fa5}', ['\u{1f6d}', '\u{399}', '\u{0}']), - ('\u{1fa6}', ['\u{1f6e}', '\u{399}', '\u{0}']), - ('\u{1fa7}', ['\u{1f6f}', '\u{399}', '\u{0}']), - ('\u{1fa8}', ['\u{1f68}', '\u{399}', '\u{0}']), - ('\u{1fa9}', ['\u{1f69}', '\u{399}', '\u{0}']), - ('\u{1faa}', ['\u{1f6a}', '\u{399}', '\u{0}']), - ('\u{1fab}', ['\u{1f6b}', '\u{399}', '\u{0}']), - ('\u{1fac}', ['\u{1f6c}', '\u{399}', '\u{0}']), - ('\u{1fad}', ['\u{1f6d}', '\u{399}', '\u{0}']), - ('\u{1fae}', ['\u{1f6e}', '\u{399}', '\u{0}']), - ('\u{1faf}', ['\u{1f6f}', '\u{399}', '\u{0}']), - ('\u{1fb0}', ['\u{1fb8}', '\u{0}', '\u{0}']), ('\u{1fb1}', ['\u{1fb9}', '\u{0}', '\u{0}']), - ('\u{1fb2}', ['\u{1fba}', '\u{399}', '\u{0}']), - ('\u{1fb3}', ['\u{391}', '\u{399}', '\u{0}']), - ('\u{1fb4}', ['\u{386}', '\u{399}', '\u{0}']), - ('\u{1fb6}', ['\u{391}', '\u{342}', '\u{0}']), - ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{399}']), - ('\u{1fbc}', ['\u{391}', '\u{399}', '\u{0}']), ('\u{1fbe}', ['\u{399}', '\u{0}', '\u{0}']), - ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\u{0}']), - ('\u{1fc3}', ['\u{397}', '\u{399}', '\u{0}']), - ('\u{1fc4}', ['\u{389}', '\u{399}', '\u{0}']), - ('\u{1fc6}', ['\u{397}', '\u{342}', '\u{0}']), - ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), - ('\u{1fcc}', ['\u{397}', '\u{399}', '\u{0}']), ('\u{1fd0}', ['\u{1fd8}', '\u{0}', '\u{0}']), - ('\u{1fd1}', ['\u{1fd9}', '\u{0}', '\u{0}']), - ('\u{1fd2}', ['\u{399}', '\u{308}', '\u{300}']), - ('\u{1fd3}', ['\u{399}', '\u{308}', '\u{301}']), - ('\u{1fd6}', ['\u{399}', '\u{342}', '\u{0}']), - ('\u{1fd7}', ['\u{399}', '\u{308}', '\u{342}']), - ('\u{1fe0}', ['\u{1fe8}', '\u{0}', '\u{0}']), ('\u{1fe1}', ['\u{1fe9}', '\u{0}', '\u{0}']), - ('\u{1fe2}', ['\u{3a5}', '\u{308}', '\u{300}']), - ('\u{1fe3}', ['\u{3a5}', '\u{308}', '\u{301}']), - ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\u{0}']), ('\u{1fe5}', ['\u{1fec}', '\u{0}', '\u{0}']), - ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\u{0}']), - ('\u{1fe7}', ['\u{3a5}', '\u{308}', '\u{342}']), - ('\u{1ff2}', ['\u{1ffa}', '\u{399}', '\u{0}']), - ('\u{1ff3}', ['\u{3a9}', '\u{399}', '\u{0}']), - ('\u{1ff4}', ['\u{38f}', '\u{399}', '\u{0}']), - ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\u{0}']), - ('\u{1ff7}', ['\u{3a9}', '\u{342}', '\u{399}']), - ('\u{1ffc}', ['\u{3a9}', '\u{399}', '\u{0}']), ('\u{214e}', ['\u{2132}', '\u{0}', '\u{0}']), - ('\u{2170}', ['\u{2160}', '\u{0}', '\u{0}']), ('\u{2171}', ['\u{2161}', '\u{0}', '\u{0}']), - ('\u{2172}', ['\u{2162}', '\u{0}', '\u{0}']), ('\u{2173}', ['\u{2163}', '\u{0}', '\u{0}']), - ('\u{2174}', ['\u{2164}', '\u{0}', '\u{0}']), ('\u{2175}', ['\u{2165}', '\u{0}', '\u{0}']), - ('\u{2176}', ['\u{2166}', '\u{0}', '\u{0}']), ('\u{2177}', ['\u{2167}', '\u{0}', '\u{0}']), - ('\u{2178}', ['\u{2168}', '\u{0}', '\u{0}']), ('\u{2179}', ['\u{2169}', '\u{0}', '\u{0}']), - ('\u{217a}', ['\u{216a}', '\u{0}', '\u{0}']), ('\u{217b}', ['\u{216b}', '\u{0}', '\u{0}']), - ('\u{217c}', ['\u{216c}', '\u{0}', '\u{0}']), ('\u{217d}', ['\u{216d}', '\u{0}', '\u{0}']), - ('\u{217e}', ['\u{216e}', '\u{0}', '\u{0}']), ('\u{217f}', ['\u{216f}', '\u{0}', '\u{0}']), - ('\u{2184}', ['\u{2183}', '\u{0}', '\u{0}']), ('\u{24d0}', ['\u{24b6}', '\u{0}', '\u{0}']), - ('\u{24d1}', ['\u{24b7}', '\u{0}', '\u{0}']), ('\u{24d2}', ['\u{24b8}', '\u{0}', '\u{0}']), - ('\u{24d3}', ['\u{24b9}', '\u{0}', '\u{0}']), ('\u{24d4}', ['\u{24ba}', '\u{0}', '\u{0}']), - ('\u{24d5}', ['\u{24bb}', '\u{0}', '\u{0}']), ('\u{24d6}', ['\u{24bc}', '\u{0}', '\u{0}']), - ('\u{24d7}', ['\u{24bd}', '\u{0}', '\u{0}']), ('\u{24d8}', ['\u{24be}', '\u{0}', '\u{0}']), - ('\u{24d9}', ['\u{24bf}', '\u{0}', '\u{0}']), ('\u{24da}', ['\u{24c0}', '\u{0}', '\u{0}']), - ('\u{24db}', ['\u{24c1}', '\u{0}', '\u{0}']), ('\u{24dc}', ['\u{24c2}', '\u{0}', '\u{0}']), - ('\u{24dd}', ['\u{24c3}', '\u{0}', '\u{0}']), ('\u{24de}', ['\u{24c4}', '\u{0}', '\u{0}']), - ('\u{24df}', ['\u{24c5}', '\u{0}', '\u{0}']), ('\u{24e0}', ['\u{24c6}', '\u{0}', '\u{0}']), - ('\u{24e1}', ['\u{24c7}', '\u{0}', '\u{0}']), ('\u{24e2}', ['\u{24c8}', '\u{0}', '\u{0}']), - ('\u{24e3}', ['\u{24c9}', '\u{0}', '\u{0}']), ('\u{24e4}', ['\u{24ca}', '\u{0}', '\u{0}']), - ('\u{24e5}', ['\u{24cb}', '\u{0}', '\u{0}']), ('\u{24e6}', ['\u{24cc}', '\u{0}', '\u{0}']), - ('\u{24e7}', ['\u{24cd}', '\u{0}', '\u{0}']), ('\u{24e8}', ['\u{24ce}', '\u{0}', '\u{0}']), - ('\u{24e9}', ['\u{24cf}', '\u{0}', '\u{0}']), ('\u{2c30}', ['\u{2c00}', '\u{0}', '\u{0}']), - ('\u{2c31}', ['\u{2c01}', '\u{0}', '\u{0}']), ('\u{2c32}', ['\u{2c02}', '\u{0}', '\u{0}']), - ('\u{2c33}', ['\u{2c03}', '\u{0}', '\u{0}']), ('\u{2c34}', ['\u{2c04}', '\u{0}', '\u{0}']), - ('\u{2c35}', ['\u{2c05}', '\u{0}', '\u{0}']), ('\u{2c36}', ['\u{2c06}', '\u{0}', '\u{0}']), - ('\u{2c37}', ['\u{2c07}', '\u{0}', '\u{0}']), ('\u{2c38}', ['\u{2c08}', '\u{0}', '\u{0}']), - ('\u{2c39}', ['\u{2c09}', '\u{0}', '\u{0}']), ('\u{2c3a}', ['\u{2c0a}', '\u{0}', '\u{0}']), - ('\u{2c3b}', ['\u{2c0b}', '\u{0}', '\u{0}']), ('\u{2c3c}', ['\u{2c0c}', '\u{0}', '\u{0}']), - ('\u{2c3d}', ['\u{2c0d}', '\u{0}', '\u{0}']), ('\u{2c3e}', ['\u{2c0e}', '\u{0}', '\u{0}']), - ('\u{2c3f}', ['\u{2c0f}', '\u{0}', '\u{0}']), ('\u{2c40}', ['\u{2c10}', '\u{0}', '\u{0}']), - ('\u{2c41}', ['\u{2c11}', '\u{0}', '\u{0}']), ('\u{2c42}', ['\u{2c12}', '\u{0}', '\u{0}']), - ('\u{2c43}', ['\u{2c13}', '\u{0}', '\u{0}']), ('\u{2c44}', ['\u{2c14}', '\u{0}', '\u{0}']), - ('\u{2c45}', ['\u{2c15}', '\u{0}', '\u{0}']), ('\u{2c46}', ['\u{2c16}', '\u{0}', '\u{0}']), - ('\u{2c47}', ['\u{2c17}', '\u{0}', '\u{0}']), ('\u{2c48}', ['\u{2c18}', '\u{0}', '\u{0}']), - ('\u{2c49}', ['\u{2c19}', '\u{0}', '\u{0}']), ('\u{2c4a}', ['\u{2c1a}', '\u{0}', '\u{0}']), - ('\u{2c4b}', ['\u{2c1b}', '\u{0}', '\u{0}']), ('\u{2c4c}', ['\u{2c1c}', '\u{0}', '\u{0}']), - ('\u{2c4d}', ['\u{2c1d}', '\u{0}', '\u{0}']), ('\u{2c4e}', ['\u{2c1e}', '\u{0}', '\u{0}']), - ('\u{2c4f}', ['\u{2c1f}', '\u{0}', '\u{0}']), ('\u{2c50}', ['\u{2c20}', '\u{0}', '\u{0}']), - ('\u{2c51}', ['\u{2c21}', '\u{0}', '\u{0}']), ('\u{2c52}', ['\u{2c22}', '\u{0}', '\u{0}']), - ('\u{2c53}', ['\u{2c23}', '\u{0}', '\u{0}']), ('\u{2c54}', ['\u{2c24}', '\u{0}', '\u{0}']), - ('\u{2c55}', ['\u{2c25}', '\u{0}', '\u{0}']), ('\u{2c56}', ['\u{2c26}', '\u{0}', '\u{0}']), - ('\u{2c57}', ['\u{2c27}', '\u{0}', '\u{0}']), ('\u{2c58}', ['\u{2c28}', '\u{0}', '\u{0}']), - ('\u{2c59}', ['\u{2c29}', '\u{0}', '\u{0}']), ('\u{2c5a}', ['\u{2c2a}', '\u{0}', '\u{0}']), - ('\u{2c5b}', ['\u{2c2b}', '\u{0}', '\u{0}']), ('\u{2c5c}', ['\u{2c2c}', '\u{0}', '\u{0}']), - ('\u{2c5d}', ['\u{2c2d}', '\u{0}', '\u{0}']), ('\u{2c5e}', ['\u{2c2e}', '\u{0}', '\u{0}']), - ('\u{2c5f}', ['\u{2c2f}', '\u{0}', '\u{0}']), ('\u{2c61}', ['\u{2c60}', '\u{0}', '\u{0}']), - ('\u{2c65}', ['\u{23a}', '\u{0}', '\u{0}']), ('\u{2c66}', ['\u{23e}', '\u{0}', '\u{0}']), - ('\u{2c68}', ['\u{2c67}', '\u{0}', '\u{0}']), ('\u{2c6a}', ['\u{2c69}', '\u{0}', '\u{0}']), - ('\u{2c6c}', ['\u{2c6b}', '\u{0}', '\u{0}']), ('\u{2c73}', ['\u{2c72}', '\u{0}', '\u{0}']), - ('\u{2c76}', ['\u{2c75}', '\u{0}', '\u{0}']), ('\u{2c81}', ['\u{2c80}', '\u{0}', '\u{0}']), - ('\u{2c83}', ['\u{2c82}', '\u{0}', '\u{0}']), ('\u{2c85}', ['\u{2c84}', '\u{0}', '\u{0}']), - ('\u{2c87}', ['\u{2c86}', '\u{0}', '\u{0}']), ('\u{2c89}', ['\u{2c88}', '\u{0}', '\u{0}']), - ('\u{2c8b}', ['\u{2c8a}', '\u{0}', '\u{0}']), ('\u{2c8d}', ['\u{2c8c}', '\u{0}', '\u{0}']), - ('\u{2c8f}', ['\u{2c8e}', '\u{0}', '\u{0}']), ('\u{2c91}', ['\u{2c90}', '\u{0}', '\u{0}']), - ('\u{2c93}', ['\u{2c92}', '\u{0}', '\u{0}']), ('\u{2c95}', ['\u{2c94}', '\u{0}', '\u{0}']), - ('\u{2c97}', ['\u{2c96}', '\u{0}', '\u{0}']), ('\u{2c99}', ['\u{2c98}', '\u{0}', '\u{0}']), - ('\u{2c9b}', ['\u{2c9a}', '\u{0}', '\u{0}']), ('\u{2c9d}', ['\u{2c9c}', '\u{0}', '\u{0}']), - ('\u{2c9f}', ['\u{2c9e}', '\u{0}', '\u{0}']), ('\u{2ca1}', ['\u{2ca0}', '\u{0}', '\u{0}']), - ('\u{2ca3}', ['\u{2ca2}', '\u{0}', '\u{0}']), ('\u{2ca5}', ['\u{2ca4}', '\u{0}', '\u{0}']), - ('\u{2ca7}', ['\u{2ca6}', '\u{0}', '\u{0}']), ('\u{2ca9}', ['\u{2ca8}', '\u{0}', '\u{0}']), - ('\u{2cab}', ['\u{2caa}', '\u{0}', '\u{0}']), ('\u{2cad}', ['\u{2cac}', '\u{0}', '\u{0}']), - ('\u{2caf}', ['\u{2cae}', '\u{0}', '\u{0}']), ('\u{2cb1}', ['\u{2cb0}', '\u{0}', '\u{0}']), - ('\u{2cb3}', ['\u{2cb2}', '\u{0}', '\u{0}']), ('\u{2cb5}', ['\u{2cb4}', '\u{0}', '\u{0}']), - ('\u{2cb7}', ['\u{2cb6}', '\u{0}', '\u{0}']), ('\u{2cb9}', ['\u{2cb8}', '\u{0}', '\u{0}']), - ('\u{2cbb}', ['\u{2cba}', '\u{0}', '\u{0}']), ('\u{2cbd}', ['\u{2cbc}', '\u{0}', '\u{0}']), - ('\u{2cbf}', ['\u{2cbe}', '\u{0}', '\u{0}']), ('\u{2cc1}', ['\u{2cc0}', '\u{0}', '\u{0}']), - ('\u{2cc3}', ['\u{2cc2}', '\u{0}', '\u{0}']), ('\u{2cc5}', ['\u{2cc4}', '\u{0}', '\u{0}']), - ('\u{2cc7}', ['\u{2cc6}', '\u{0}', '\u{0}']), ('\u{2cc9}', ['\u{2cc8}', '\u{0}', '\u{0}']), - ('\u{2ccb}', ['\u{2cca}', '\u{0}', '\u{0}']), ('\u{2ccd}', ['\u{2ccc}', '\u{0}', '\u{0}']), - ('\u{2ccf}', ['\u{2cce}', '\u{0}', '\u{0}']), ('\u{2cd1}', ['\u{2cd0}', '\u{0}', '\u{0}']), - ('\u{2cd3}', ['\u{2cd2}', '\u{0}', '\u{0}']), ('\u{2cd5}', ['\u{2cd4}', '\u{0}', '\u{0}']), - ('\u{2cd7}', ['\u{2cd6}', '\u{0}', '\u{0}']), ('\u{2cd9}', ['\u{2cd8}', '\u{0}', '\u{0}']), - ('\u{2cdb}', ['\u{2cda}', '\u{0}', '\u{0}']), ('\u{2cdd}', ['\u{2cdc}', '\u{0}', '\u{0}']), - ('\u{2cdf}', ['\u{2cde}', '\u{0}', '\u{0}']), ('\u{2ce1}', ['\u{2ce0}', '\u{0}', '\u{0}']), - ('\u{2ce3}', ['\u{2ce2}', '\u{0}', '\u{0}']), ('\u{2cec}', ['\u{2ceb}', '\u{0}', '\u{0}']), - ('\u{2cee}', ['\u{2ced}', '\u{0}', '\u{0}']), ('\u{2cf3}', ['\u{2cf2}', '\u{0}', '\u{0}']), - ('\u{2d00}', ['\u{10a0}', '\u{0}', '\u{0}']), ('\u{2d01}', ['\u{10a1}', '\u{0}', '\u{0}']), - ('\u{2d02}', ['\u{10a2}', '\u{0}', '\u{0}']), ('\u{2d03}', ['\u{10a3}', '\u{0}', '\u{0}']), - ('\u{2d04}', ['\u{10a4}', '\u{0}', '\u{0}']), ('\u{2d05}', ['\u{10a5}', '\u{0}', '\u{0}']), - ('\u{2d06}', ['\u{10a6}', '\u{0}', '\u{0}']), ('\u{2d07}', ['\u{10a7}', '\u{0}', '\u{0}']), - ('\u{2d08}', ['\u{10a8}', '\u{0}', '\u{0}']), ('\u{2d09}', ['\u{10a9}', '\u{0}', '\u{0}']), - ('\u{2d0a}', ['\u{10aa}', '\u{0}', '\u{0}']), ('\u{2d0b}', ['\u{10ab}', '\u{0}', '\u{0}']), - ('\u{2d0c}', ['\u{10ac}', '\u{0}', '\u{0}']), ('\u{2d0d}', ['\u{10ad}', '\u{0}', '\u{0}']), - ('\u{2d0e}', ['\u{10ae}', '\u{0}', '\u{0}']), ('\u{2d0f}', ['\u{10af}', '\u{0}', '\u{0}']), - ('\u{2d10}', ['\u{10b0}', '\u{0}', '\u{0}']), ('\u{2d11}', ['\u{10b1}', '\u{0}', '\u{0}']), - ('\u{2d12}', ['\u{10b2}', '\u{0}', '\u{0}']), ('\u{2d13}', ['\u{10b3}', '\u{0}', '\u{0}']), - ('\u{2d14}', ['\u{10b4}', '\u{0}', '\u{0}']), ('\u{2d15}', ['\u{10b5}', '\u{0}', '\u{0}']), - ('\u{2d16}', ['\u{10b6}', '\u{0}', '\u{0}']), ('\u{2d17}', ['\u{10b7}', '\u{0}', '\u{0}']), - ('\u{2d18}', ['\u{10b8}', '\u{0}', '\u{0}']), ('\u{2d19}', ['\u{10b9}', '\u{0}', '\u{0}']), - ('\u{2d1a}', ['\u{10ba}', '\u{0}', '\u{0}']), ('\u{2d1b}', ['\u{10bb}', '\u{0}', '\u{0}']), - ('\u{2d1c}', ['\u{10bc}', '\u{0}', '\u{0}']), ('\u{2d1d}', ['\u{10bd}', '\u{0}', '\u{0}']), - ('\u{2d1e}', ['\u{10be}', '\u{0}', '\u{0}']), ('\u{2d1f}', ['\u{10bf}', '\u{0}', '\u{0}']), - ('\u{2d20}', ['\u{10c0}', '\u{0}', '\u{0}']), ('\u{2d21}', ['\u{10c1}', '\u{0}', '\u{0}']), - ('\u{2d22}', ['\u{10c2}', '\u{0}', '\u{0}']), ('\u{2d23}', ['\u{10c3}', '\u{0}', '\u{0}']), - ('\u{2d24}', ['\u{10c4}', '\u{0}', '\u{0}']), ('\u{2d25}', ['\u{10c5}', '\u{0}', '\u{0}']), - ('\u{2d27}', ['\u{10c7}', '\u{0}', '\u{0}']), ('\u{2d2d}', ['\u{10cd}', '\u{0}', '\u{0}']), - ('\u{a641}', ['\u{a640}', '\u{0}', '\u{0}']), ('\u{a643}', ['\u{a642}', '\u{0}', '\u{0}']), - ('\u{a645}', ['\u{a644}', '\u{0}', '\u{0}']), ('\u{a647}', ['\u{a646}', '\u{0}', '\u{0}']), - ('\u{a649}', ['\u{a648}', '\u{0}', '\u{0}']), ('\u{a64b}', ['\u{a64a}', '\u{0}', '\u{0}']), - ('\u{a64d}', ['\u{a64c}', '\u{0}', '\u{0}']), ('\u{a64f}', ['\u{a64e}', '\u{0}', '\u{0}']), - ('\u{a651}', ['\u{a650}', '\u{0}', '\u{0}']), ('\u{a653}', ['\u{a652}', '\u{0}', '\u{0}']), - ('\u{a655}', ['\u{a654}', '\u{0}', '\u{0}']), ('\u{a657}', ['\u{a656}', '\u{0}', '\u{0}']), - ('\u{a659}', ['\u{a658}', '\u{0}', '\u{0}']), ('\u{a65b}', ['\u{a65a}', '\u{0}', '\u{0}']), - ('\u{a65d}', ['\u{a65c}', '\u{0}', '\u{0}']), ('\u{a65f}', ['\u{a65e}', '\u{0}', '\u{0}']), - ('\u{a661}', ['\u{a660}', '\u{0}', '\u{0}']), ('\u{a663}', ['\u{a662}', '\u{0}', '\u{0}']), - ('\u{a665}', ['\u{a664}', '\u{0}', '\u{0}']), ('\u{a667}', ['\u{a666}', '\u{0}', '\u{0}']), - ('\u{a669}', ['\u{a668}', '\u{0}', '\u{0}']), ('\u{a66b}', ['\u{a66a}', '\u{0}', '\u{0}']), - ('\u{a66d}', ['\u{a66c}', '\u{0}', '\u{0}']), ('\u{a681}', ['\u{a680}', '\u{0}', '\u{0}']), - ('\u{a683}', ['\u{a682}', '\u{0}', '\u{0}']), ('\u{a685}', ['\u{a684}', '\u{0}', '\u{0}']), - ('\u{a687}', ['\u{a686}', '\u{0}', '\u{0}']), ('\u{a689}', ['\u{a688}', '\u{0}', '\u{0}']), - ('\u{a68b}', ['\u{a68a}', '\u{0}', '\u{0}']), ('\u{a68d}', ['\u{a68c}', '\u{0}', '\u{0}']), - ('\u{a68f}', ['\u{a68e}', '\u{0}', '\u{0}']), ('\u{a691}', ['\u{a690}', '\u{0}', '\u{0}']), - ('\u{a693}', ['\u{a692}', '\u{0}', '\u{0}']), ('\u{a695}', ['\u{a694}', '\u{0}', '\u{0}']), - ('\u{a697}', ['\u{a696}', '\u{0}', '\u{0}']), ('\u{a699}', ['\u{a698}', '\u{0}', '\u{0}']), - ('\u{a69b}', ['\u{a69a}', '\u{0}', '\u{0}']), ('\u{a723}', ['\u{a722}', '\u{0}', '\u{0}']), - ('\u{a725}', ['\u{a724}', '\u{0}', '\u{0}']), ('\u{a727}', ['\u{a726}', '\u{0}', '\u{0}']), - ('\u{a729}', ['\u{a728}', '\u{0}', '\u{0}']), ('\u{a72b}', ['\u{a72a}', '\u{0}', '\u{0}']), - ('\u{a72d}', ['\u{a72c}', '\u{0}', '\u{0}']), ('\u{a72f}', ['\u{a72e}', '\u{0}', '\u{0}']), - ('\u{a733}', ['\u{a732}', '\u{0}', '\u{0}']), ('\u{a735}', ['\u{a734}', '\u{0}', '\u{0}']), - ('\u{a737}', ['\u{a736}', '\u{0}', '\u{0}']), ('\u{a739}', ['\u{a738}', '\u{0}', '\u{0}']), - ('\u{a73b}', ['\u{a73a}', '\u{0}', '\u{0}']), ('\u{a73d}', ['\u{a73c}', '\u{0}', '\u{0}']), - ('\u{a73f}', ['\u{a73e}', '\u{0}', '\u{0}']), ('\u{a741}', ['\u{a740}', '\u{0}', '\u{0}']), - ('\u{a743}', ['\u{a742}', '\u{0}', '\u{0}']), ('\u{a745}', ['\u{a744}', '\u{0}', '\u{0}']), - ('\u{a747}', ['\u{a746}', '\u{0}', '\u{0}']), ('\u{a749}', ['\u{a748}', '\u{0}', '\u{0}']), - ('\u{a74b}', ['\u{a74a}', '\u{0}', '\u{0}']), ('\u{a74d}', ['\u{a74c}', '\u{0}', '\u{0}']), - ('\u{a74f}', ['\u{a74e}', '\u{0}', '\u{0}']), ('\u{a751}', ['\u{a750}', '\u{0}', '\u{0}']), - ('\u{a753}', ['\u{a752}', '\u{0}', '\u{0}']), ('\u{a755}', ['\u{a754}', '\u{0}', '\u{0}']), - ('\u{a757}', ['\u{a756}', '\u{0}', '\u{0}']), ('\u{a759}', ['\u{a758}', '\u{0}', '\u{0}']), - ('\u{a75b}', ['\u{a75a}', '\u{0}', '\u{0}']), ('\u{a75d}', ['\u{a75c}', '\u{0}', '\u{0}']), - ('\u{a75f}', ['\u{a75e}', '\u{0}', '\u{0}']), ('\u{a761}', ['\u{a760}', '\u{0}', '\u{0}']), - ('\u{a763}', ['\u{a762}', '\u{0}', '\u{0}']), ('\u{a765}', ['\u{a764}', '\u{0}', '\u{0}']), - ('\u{a767}', ['\u{a766}', '\u{0}', '\u{0}']), ('\u{a769}', ['\u{a768}', '\u{0}', '\u{0}']), - ('\u{a76b}', ['\u{a76a}', '\u{0}', '\u{0}']), ('\u{a76d}', ['\u{a76c}', '\u{0}', '\u{0}']), - ('\u{a76f}', ['\u{a76e}', '\u{0}', '\u{0}']), ('\u{a77a}', ['\u{a779}', '\u{0}', '\u{0}']), - ('\u{a77c}', ['\u{a77b}', '\u{0}', '\u{0}']), ('\u{a77f}', ['\u{a77e}', '\u{0}', '\u{0}']), - ('\u{a781}', ['\u{a780}', '\u{0}', '\u{0}']), ('\u{a783}', ['\u{a782}', '\u{0}', '\u{0}']), - ('\u{a785}', ['\u{a784}', '\u{0}', '\u{0}']), ('\u{a787}', ['\u{a786}', '\u{0}', '\u{0}']), - ('\u{a78c}', ['\u{a78b}', '\u{0}', '\u{0}']), ('\u{a791}', ['\u{a790}', '\u{0}', '\u{0}']), - ('\u{a793}', ['\u{a792}', '\u{0}', '\u{0}']), ('\u{a794}', ['\u{a7c4}', '\u{0}', '\u{0}']), - ('\u{a797}', ['\u{a796}', '\u{0}', '\u{0}']), ('\u{a799}', ['\u{a798}', '\u{0}', '\u{0}']), - ('\u{a79b}', ['\u{a79a}', '\u{0}', '\u{0}']), ('\u{a79d}', ['\u{a79c}', '\u{0}', '\u{0}']), - ('\u{a79f}', ['\u{a79e}', '\u{0}', '\u{0}']), ('\u{a7a1}', ['\u{a7a0}', '\u{0}', '\u{0}']), - ('\u{a7a3}', ['\u{a7a2}', '\u{0}', '\u{0}']), ('\u{a7a5}', ['\u{a7a4}', '\u{0}', '\u{0}']), - ('\u{a7a7}', ['\u{a7a6}', '\u{0}', '\u{0}']), ('\u{a7a9}', ['\u{a7a8}', '\u{0}', '\u{0}']), - ('\u{a7b5}', ['\u{a7b4}', '\u{0}', '\u{0}']), ('\u{a7b7}', ['\u{a7b6}', '\u{0}', '\u{0}']), - ('\u{a7b9}', ['\u{a7b8}', '\u{0}', '\u{0}']), ('\u{a7bb}', ['\u{a7ba}', '\u{0}', '\u{0}']), - ('\u{a7bd}', ['\u{a7bc}', '\u{0}', '\u{0}']), ('\u{a7bf}', ['\u{a7be}', '\u{0}', '\u{0}']), - ('\u{a7c1}', ['\u{a7c0}', '\u{0}', '\u{0}']), ('\u{a7c3}', ['\u{a7c2}', '\u{0}', '\u{0}']), - ('\u{a7c8}', ['\u{a7c7}', '\u{0}', '\u{0}']), ('\u{a7ca}', ['\u{a7c9}', '\u{0}', '\u{0}']), - ('\u{a7d1}', ['\u{a7d0}', '\u{0}', '\u{0}']), ('\u{a7d7}', ['\u{a7d6}', '\u{0}', '\u{0}']), - ('\u{a7d9}', ['\u{a7d8}', '\u{0}', '\u{0}']), ('\u{a7f6}', ['\u{a7f5}', '\u{0}', '\u{0}']), - ('\u{ab53}', ['\u{a7b3}', '\u{0}', '\u{0}']), ('\u{ab70}', ['\u{13a0}', '\u{0}', '\u{0}']), - ('\u{ab71}', ['\u{13a1}', '\u{0}', '\u{0}']), ('\u{ab72}', ['\u{13a2}', '\u{0}', '\u{0}']), - ('\u{ab73}', ['\u{13a3}', '\u{0}', '\u{0}']), ('\u{ab74}', ['\u{13a4}', '\u{0}', '\u{0}']), - ('\u{ab75}', ['\u{13a5}', '\u{0}', '\u{0}']), ('\u{ab76}', ['\u{13a6}', '\u{0}', '\u{0}']), - ('\u{ab77}', ['\u{13a7}', '\u{0}', '\u{0}']), ('\u{ab78}', ['\u{13a8}', '\u{0}', '\u{0}']), - ('\u{ab79}', ['\u{13a9}', '\u{0}', '\u{0}']), ('\u{ab7a}', ['\u{13aa}', '\u{0}', '\u{0}']), - ('\u{ab7b}', ['\u{13ab}', '\u{0}', '\u{0}']), ('\u{ab7c}', ['\u{13ac}', '\u{0}', '\u{0}']), - ('\u{ab7d}', ['\u{13ad}', '\u{0}', '\u{0}']), ('\u{ab7e}', ['\u{13ae}', '\u{0}', '\u{0}']), - ('\u{ab7f}', ['\u{13af}', '\u{0}', '\u{0}']), ('\u{ab80}', ['\u{13b0}', '\u{0}', '\u{0}']), - ('\u{ab81}', ['\u{13b1}', '\u{0}', '\u{0}']), ('\u{ab82}', ['\u{13b2}', '\u{0}', '\u{0}']), - ('\u{ab83}', ['\u{13b3}', '\u{0}', '\u{0}']), ('\u{ab84}', ['\u{13b4}', '\u{0}', '\u{0}']), - ('\u{ab85}', ['\u{13b5}', '\u{0}', '\u{0}']), ('\u{ab86}', ['\u{13b6}', '\u{0}', '\u{0}']), - ('\u{ab87}', ['\u{13b7}', '\u{0}', '\u{0}']), ('\u{ab88}', ['\u{13b8}', '\u{0}', '\u{0}']), - ('\u{ab89}', ['\u{13b9}', '\u{0}', '\u{0}']), ('\u{ab8a}', ['\u{13ba}', '\u{0}', '\u{0}']), - ('\u{ab8b}', ['\u{13bb}', '\u{0}', '\u{0}']), ('\u{ab8c}', ['\u{13bc}', '\u{0}', '\u{0}']), - ('\u{ab8d}', ['\u{13bd}', '\u{0}', '\u{0}']), ('\u{ab8e}', ['\u{13be}', '\u{0}', '\u{0}']), - ('\u{ab8f}', ['\u{13bf}', '\u{0}', '\u{0}']), ('\u{ab90}', ['\u{13c0}', '\u{0}', '\u{0}']), - ('\u{ab91}', ['\u{13c1}', '\u{0}', '\u{0}']), ('\u{ab92}', ['\u{13c2}', '\u{0}', '\u{0}']), - ('\u{ab93}', ['\u{13c3}', '\u{0}', '\u{0}']), ('\u{ab94}', ['\u{13c4}', '\u{0}', '\u{0}']), - ('\u{ab95}', ['\u{13c5}', '\u{0}', '\u{0}']), ('\u{ab96}', ['\u{13c6}', '\u{0}', '\u{0}']), - ('\u{ab97}', ['\u{13c7}', '\u{0}', '\u{0}']), ('\u{ab98}', ['\u{13c8}', '\u{0}', '\u{0}']), - ('\u{ab99}', ['\u{13c9}', '\u{0}', '\u{0}']), ('\u{ab9a}', ['\u{13ca}', '\u{0}', '\u{0}']), - ('\u{ab9b}', ['\u{13cb}', '\u{0}', '\u{0}']), ('\u{ab9c}', ['\u{13cc}', '\u{0}', '\u{0}']), - ('\u{ab9d}', ['\u{13cd}', '\u{0}', '\u{0}']), ('\u{ab9e}', ['\u{13ce}', '\u{0}', '\u{0}']), - ('\u{ab9f}', ['\u{13cf}', '\u{0}', '\u{0}']), ('\u{aba0}', ['\u{13d0}', '\u{0}', '\u{0}']), - ('\u{aba1}', ['\u{13d1}', '\u{0}', '\u{0}']), ('\u{aba2}', ['\u{13d2}', '\u{0}', '\u{0}']), - ('\u{aba3}', ['\u{13d3}', '\u{0}', '\u{0}']), ('\u{aba4}', ['\u{13d4}', '\u{0}', '\u{0}']), - ('\u{aba5}', ['\u{13d5}', '\u{0}', '\u{0}']), ('\u{aba6}', ['\u{13d6}', '\u{0}', '\u{0}']), - ('\u{aba7}', ['\u{13d7}', '\u{0}', '\u{0}']), ('\u{aba8}', ['\u{13d8}', '\u{0}', '\u{0}']), - ('\u{aba9}', ['\u{13d9}', '\u{0}', '\u{0}']), ('\u{abaa}', ['\u{13da}', '\u{0}', '\u{0}']), - ('\u{abab}', ['\u{13db}', '\u{0}', '\u{0}']), ('\u{abac}', ['\u{13dc}', '\u{0}', '\u{0}']), - ('\u{abad}', ['\u{13dd}', '\u{0}', '\u{0}']), ('\u{abae}', ['\u{13de}', '\u{0}', '\u{0}']), - ('\u{abaf}', ['\u{13df}', '\u{0}', '\u{0}']), ('\u{abb0}', ['\u{13e0}', '\u{0}', '\u{0}']), - ('\u{abb1}', ['\u{13e1}', '\u{0}', '\u{0}']), ('\u{abb2}', ['\u{13e2}', '\u{0}', '\u{0}']), - ('\u{abb3}', ['\u{13e3}', '\u{0}', '\u{0}']), ('\u{abb4}', ['\u{13e4}', '\u{0}', '\u{0}']), - ('\u{abb5}', ['\u{13e5}', '\u{0}', '\u{0}']), ('\u{abb6}', ['\u{13e6}', '\u{0}', '\u{0}']), - ('\u{abb7}', ['\u{13e7}', '\u{0}', '\u{0}']), ('\u{abb8}', ['\u{13e8}', '\u{0}', '\u{0}']), - ('\u{abb9}', ['\u{13e9}', '\u{0}', '\u{0}']), ('\u{abba}', ['\u{13ea}', '\u{0}', '\u{0}']), - ('\u{abbb}', ['\u{13eb}', '\u{0}', '\u{0}']), ('\u{abbc}', ['\u{13ec}', '\u{0}', '\u{0}']), - ('\u{abbd}', ['\u{13ed}', '\u{0}', '\u{0}']), ('\u{abbe}', ['\u{13ee}', '\u{0}', '\u{0}']), - ('\u{abbf}', ['\u{13ef}', '\u{0}', '\u{0}']), ('\u{fb00}', ['F', 'F', '\u{0}']), - ('\u{fb01}', ['F', 'I', '\u{0}']), ('\u{fb02}', ['F', 'L', '\u{0}']), - ('\u{fb03}', ['F', 'F', 'I']), ('\u{fb04}', ['F', 'F', 'L']), - ('\u{fb05}', ['S', 'T', '\u{0}']), ('\u{fb06}', ['S', 'T', '\u{0}']), - ('\u{fb13}', ['\u{544}', '\u{546}', '\u{0}']), - ('\u{fb14}', ['\u{544}', '\u{535}', '\u{0}']), - ('\u{fb15}', ['\u{544}', '\u{53b}', '\u{0}']), - ('\u{fb16}', ['\u{54e}', '\u{546}', '\u{0}']), - ('\u{fb17}', ['\u{544}', '\u{53d}', '\u{0}']), ('\u{ff41}', ['\u{ff21}', '\u{0}', '\u{0}']), - ('\u{ff42}', ['\u{ff22}', '\u{0}', '\u{0}']), ('\u{ff43}', ['\u{ff23}', '\u{0}', '\u{0}']), - ('\u{ff44}', ['\u{ff24}', '\u{0}', '\u{0}']), ('\u{ff45}', ['\u{ff25}', '\u{0}', '\u{0}']), - ('\u{ff46}', ['\u{ff26}', '\u{0}', '\u{0}']), ('\u{ff47}', ['\u{ff27}', '\u{0}', '\u{0}']), - ('\u{ff48}', ['\u{ff28}', '\u{0}', '\u{0}']), ('\u{ff49}', ['\u{ff29}', '\u{0}', '\u{0}']), - ('\u{ff4a}', ['\u{ff2a}', '\u{0}', '\u{0}']), ('\u{ff4b}', ['\u{ff2b}', '\u{0}', '\u{0}']), - ('\u{ff4c}', ['\u{ff2c}', '\u{0}', '\u{0}']), ('\u{ff4d}', ['\u{ff2d}', '\u{0}', '\u{0}']), - ('\u{ff4e}', ['\u{ff2e}', '\u{0}', '\u{0}']), ('\u{ff4f}', ['\u{ff2f}', '\u{0}', '\u{0}']), - ('\u{ff50}', ['\u{ff30}', '\u{0}', '\u{0}']), ('\u{ff51}', ['\u{ff31}', '\u{0}', '\u{0}']), - ('\u{ff52}', ['\u{ff32}', '\u{0}', '\u{0}']), ('\u{ff53}', ['\u{ff33}', '\u{0}', '\u{0}']), - ('\u{ff54}', ['\u{ff34}', '\u{0}', '\u{0}']), ('\u{ff55}', ['\u{ff35}', '\u{0}', '\u{0}']), - ('\u{ff56}', ['\u{ff36}', '\u{0}', '\u{0}']), ('\u{ff57}', ['\u{ff37}', '\u{0}', '\u{0}']), - ('\u{ff58}', ['\u{ff38}', '\u{0}', '\u{0}']), ('\u{ff59}', ['\u{ff39}', '\u{0}', '\u{0}']), - ('\u{ff5a}', ['\u{ff3a}', '\u{0}', '\u{0}']), - ('\u{10428}', ['\u{10400}', '\u{0}', '\u{0}']), - ('\u{10429}', ['\u{10401}', '\u{0}', '\u{0}']), - ('\u{1042a}', ['\u{10402}', '\u{0}', '\u{0}']), - ('\u{1042b}', ['\u{10403}', '\u{0}', '\u{0}']), - ('\u{1042c}', ['\u{10404}', '\u{0}', '\u{0}']), - ('\u{1042d}', ['\u{10405}', '\u{0}', '\u{0}']), - ('\u{1042e}', ['\u{10406}', '\u{0}', '\u{0}']), - ('\u{1042f}', ['\u{10407}', '\u{0}', '\u{0}']), - ('\u{10430}', ['\u{10408}', '\u{0}', '\u{0}']), - ('\u{10431}', ['\u{10409}', '\u{0}', '\u{0}']), - ('\u{10432}', ['\u{1040a}', '\u{0}', '\u{0}']), - ('\u{10433}', ['\u{1040b}', '\u{0}', '\u{0}']), - ('\u{10434}', ['\u{1040c}', '\u{0}', '\u{0}']), - ('\u{10435}', ['\u{1040d}', '\u{0}', '\u{0}']), - ('\u{10436}', ['\u{1040e}', '\u{0}', '\u{0}']), - ('\u{10437}', ['\u{1040f}', '\u{0}', '\u{0}']), - ('\u{10438}', ['\u{10410}', '\u{0}', '\u{0}']), - ('\u{10439}', ['\u{10411}', '\u{0}', '\u{0}']), - ('\u{1043a}', ['\u{10412}', '\u{0}', '\u{0}']), - ('\u{1043b}', ['\u{10413}', '\u{0}', '\u{0}']), - ('\u{1043c}', ['\u{10414}', '\u{0}', '\u{0}']), - ('\u{1043d}', ['\u{10415}', '\u{0}', '\u{0}']), - ('\u{1043e}', ['\u{10416}', '\u{0}', '\u{0}']), - ('\u{1043f}', ['\u{10417}', '\u{0}', '\u{0}']), - ('\u{10440}', ['\u{10418}', '\u{0}', '\u{0}']), - ('\u{10441}', ['\u{10419}', '\u{0}', '\u{0}']), - ('\u{10442}', ['\u{1041a}', '\u{0}', '\u{0}']), - ('\u{10443}', ['\u{1041b}', '\u{0}', '\u{0}']), - ('\u{10444}', ['\u{1041c}', '\u{0}', '\u{0}']), - ('\u{10445}', ['\u{1041d}', '\u{0}', '\u{0}']), - ('\u{10446}', ['\u{1041e}', '\u{0}', '\u{0}']), - ('\u{10447}', ['\u{1041f}', '\u{0}', '\u{0}']), - ('\u{10448}', ['\u{10420}', '\u{0}', '\u{0}']), - ('\u{10449}', ['\u{10421}', '\u{0}', '\u{0}']), - ('\u{1044a}', ['\u{10422}', '\u{0}', '\u{0}']), - ('\u{1044b}', ['\u{10423}', '\u{0}', '\u{0}']), - ('\u{1044c}', ['\u{10424}', '\u{0}', '\u{0}']), - ('\u{1044d}', ['\u{10425}', '\u{0}', '\u{0}']), - ('\u{1044e}', ['\u{10426}', '\u{0}', '\u{0}']), - ('\u{1044f}', ['\u{10427}', '\u{0}', '\u{0}']), - ('\u{104d8}', ['\u{104b0}', '\u{0}', '\u{0}']), - ('\u{104d9}', ['\u{104b1}', '\u{0}', '\u{0}']), - ('\u{104da}', ['\u{104b2}', '\u{0}', '\u{0}']), - ('\u{104db}', ['\u{104b3}', '\u{0}', '\u{0}']), - ('\u{104dc}', ['\u{104b4}', '\u{0}', '\u{0}']), - ('\u{104dd}', ['\u{104b5}', '\u{0}', '\u{0}']), - ('\u{104de}', ['\u{104b6}', '\u{0}', '\u{0}']), - ('\u{104df}', ['\u{104b7}', '\u{0}', '\u{0}']), - ('\u{104e0}', ['\u{104b8}', '\u{0}', '\u{0}']), - ('\u{104e1}', ['\u{104b9}', '\u{0}', '\u{0}']), - ('\u{104e2}', ['\u{104ba}', '\u{0}', '\u{0}']), - ('\u{104e3}', ['\u{104bb}', '\u{0}', '\u{0}']), - ('\u{104e4}', ['\u{104bc}', '\u{0}', '\u{0}']), - ('\u{104e5}', ['\u{104bd}', '\u{0}', '\u{0}']), - ('\u{104e6}', ['\u{104be}', '\u{0}', '\u{0}']), - ('\u{104e7}', ['\u{104bf}', '\u{0}', '\u{0}']), - ('\u{104e8}', ['\u{104c0}', '\u{0}', '\u{0}']), - ('\u{104e9}', ['\u{104c1}', '\u{0}', '\u{0}']), - ('\u{104ea}', ['\u{104c2}', '\u{0}', '\u{0}']), - ('\u{104eb}', ['\u{104c3}', '\u{0}', '\u{0}']), - ('\u{104ec}', ['\u{104c4}', '\u{0}', '\u{0}']), - ('\u{104ed}', ['\u{104c5}', '\u{0}', '\u{0}']), - ('\u{104ee}', ['\u{104c6}', '\u{0}', '\u{0}']), - ('\u{104ef}', ['\u{104c7}', '\u{0}', '\u{0}']), - ('\u{104f0}', ['\u{104c8}', '\u{0}', '\u{0}']), - ('\u{104f1}', ['\u{104c9}', '\u{0}', '\u{0}']), - ('\u{104f2}', ['\u{104ca}', '\u{0}', '\u{0}']), - ('\u{104f3}', ['\u{104cb}', '\u{0}', '\u{0}']), - ('\u{104f4}', ['\u{104cc}', '\u{0}', '\u{0}']), - ('\u{104f5}', ['\u{104cd}', '\u{0}', '\u{0}']), - ('\u{104f6}', ['\u{104ce}', '\u{0}', '\u{0}']), - ('\u{104f7}', ['\u{104cf}', '\u{0}', '\u{0}']), - ('\u{104f8}', ['\u{104d0}', '\u{0}', '\u{0}']), - ('\u{104f9}', ['\u{104d1}', '\u{0}', '\u{0}']), - ('\u{104fa}', ['\u{104d2}', '\u{0}', '\u{0}']), - ('\u{104fb}', ['\u{104d3}', '\u{0}', '\u{0}']), - ('\u{10597}', ['\u{10570}', '\u{0}', '\u{0}']), - ('\u{10598}', ['\u{10571}', '\u{0}', '\u{0}']), - ('\u{10599}', ['\u{10572}', '\u{0}', '\u{0}']), - ('\u{1059a}', ['\u{10573}', '\u{0}', '\u{0}']), - ('\u{1059b}', ['\u{10574}', '\u{0}', '\u{0}']), - ('\u{1059c}', ['\u{10575}', '\u{0}', '\u{0}']), - ('\u{1059d}', ['\u{10576}', '\u{0}', '\u{0}']), - ('\u{1059e}', ['\u{10577}', '\u{0}', '\u{0}']), - ('\u{1059f}', ['\u{10578}', '\u{0}', '\u{0}']), - ('\u{105a0}', ['\u{10579}', '\u{0}', '\u{0}']), - ('\u{105a1}', ['\u{1057a}', '\u{0}', '\u{0}']), - ('\u{105a3}', ['\u{1057c}', '\u{0}', '\u{0}']), - ('\u{105a4}', ['\u{1057d}', '\u{0}', '\u{0}']), - ('\u{105a5}', ['\u{1057e}', '\u{0}', '\u{0}']), - ('\u{105a6}', ['\u{1057f}', '\u{0}', '\u{0}']), - ('\u{105a7}', ['\u{10580}', '\u{0}', '\u{0}']), - ('\u{105a8}', ['\u{10581}', '\u{0}', '\u{0}']), - ('\u{105a9}', ['\u{10582}', '\u{0}', '\u{0}']), - ('\u{105aa}', ['\u{10583}', '\u{0}', '\u{0}']), - ('\u{105ab}', ['\u{10584}', '\u{0}', '\u{0}']), - ('\u{105ac}', ['\u{10585}', '\u{0}', '\u{0}']), - ('\u{105ad}', ['\u{10586}', '\u{0}', '\u{0}']), - ('\u{105ae}', ['\u{10587}', '\u{0}', '\u{0}']), - ('\u{105af}', ['\u{10588}', '\u{0}', '\u{0}']), - ('\u{105b0}', ['\u{10589}', '\u{0}', '\u{0}']), - ('\u{105b1}', ['\u{1058a}', '\u{0}', '\u{0}']), - ('\u{105b3}', ['\u{1058c}', '\u{0}', '\u{0}']), - ('\u{105b4}', ['\u{1058d}', '\u{0}', '\u{0}']), - ('\u{105b5}', ['\u{1058e}', '\u{0}', '\u{0}']), - ('\u{105b6}', ['\u{1058f}', '\u{0}', '\u{0}']), - ('\u{105b7}', ['\u{10590}', '\u{0}', '\u{0}']), - ('\u{105b8}', ['\u{10591}', '\u{0}', '\u{0}']), - ('\u{105b9}', ['\u{10592}', '\u{0}', '\u{0}']), - ('\u{105bb}', ['\u{10594}', '\u{0}', '\u{0}']), - ('\u{105bc}', ['\u{10595}', '\u{0}', '\u{0}']), - ('\u{10cc0}', ['\u{10c80}', '\u{0}', '\u{0}']), - ('\u{10cc1}', ['\u{10c81}', '\u{0}', '\u{0}']), - ('\u{10cc2}', ['\u{10c82}', '\u{0}', '\u{0}']), - ('\u{10cc3}', ['\u{10c83}', '\u{0}', '\u{0}']), - ('\u{10cc4}', ['\u{10c84}', '\u{0}', '\u{0}']), - ('\u{10cc5}', ['\u{10c85}', '\u{0}', '\u{0}']), - ('\u{10cc6}', ['\u{10c86}', '\u{0}', '\u{0}']), - ('\u{10cc7}', ['\u{10c87}', '\u{0}', '\u{0}']), - ('\u{10cc8}', ['\u{10c88}', '\u{0}', '\u{0}']), - ('\u{10cc9}', ['\u{10c89}', '\u{0}', '\u{0}']), - ('\u{10cca}', ['\u{10c8a}', '\u{0}', '\u{0}']), - ('\u{10ccb}', ['\u{10c8b}', '\u{0}', '\u{0}']), - ('\u{10ccc}', ['\u{10c8c}', '\u{0}', '\u{0}']), - ('\u{10ccd}', ['\u{10c8d}', '\u{0}', '\u{0}']), - ('\u{10cce}', ['\u{10c8e}', '\u{0}', '\u{0}']), - ('\u{10ccf}', ['\u{10c8f}', '\u{0}', '\u{0}']), - ('\u{10cd0}', ['\u{10c90}', '\u{0}', '\u{0}']), - ('\u{10cd1}', ['\u{10c91}', '\u{0}', '\u{0}']), - ('\u{10cd2}', ['\u{10c92}', '\u{0}', '\u{0}']), - ('\u{10cd3}', ['\u{10c93}', '\u{0}', '\u{0}']), - ('\u{10cd4}', ['\u{10c94}', '\u{0}', '\u{0}']), - ('\u{10cd5}', ['\u{10c95}', '\u{0}', '\u{0}']), - ('\u{10cd6}', ['\u{10c96}', '\u{0}', '\u{0}']), - ('\u{10cd7}', ['\u{10c97}', '\u{0}', '\u{0}']), - ('\u{10cd8}', ['\u{10c98}', '\u{0}', '\u{0}']), - ('\u{10cd9}', ['\u{10c99}', '\u{0}', '\u{0}']), - ('\u{10cda}', ['\u{10c9a}', '\u{0}', '\u{0}']), - ('\u{10cdb}', ['\u{10c9b}', '\u{0}', '\u{0}']), - ('\u{10cdc}', ['\u{10c9c}', '\u{0}', '\u{0}']), - ('\u{10cdd}', ['\u{10c9d}', '\u{0}', '\u{0}']), - ('\u{10cde}', ['\u{10c9e}', '\u{0}', '\u{0}']), - ('\u{10cdf}', ['\u{10c9f}', '\u{0}', '\u{0}']), - ('\u{10ce0}', ['\u{10ca0}', '\u{0}', '\u{0}']), - ('\u{10ce1}', ['\u{10ca1}', '\u{0}', '\u{0}']), - ('\u{10ce2}', ['\u{10ca2}', '\u{0}', '\u{0}']), - ('\u{10ce3}', ['\u{10ca3}', '\u{0}', '\u{0}']), - ('\u{10ce4}', ['\u{10ca4}', '\u{0}', '\u{0}']), - ('\u{10ce5}', ['\u{10ca5}', '\u{0}', '\u{0}']), - ('\u{10ce6}', ['\u{10ca6}', '\u{0}', '\u{0}']), - ('\u{10ce7}', ['\u{10ca7}', '\u{0}', '\u{0}']), - ('\u{10ce8}', ['\u{10ca8}', '\u{0}', '\u{0}']), - ('\u{10ce9}', ['\u{10ca9}', '\u{0}', '\u{0}']), - ('\u{10cea}', ['\u{10caa}', '\u{0}', '\u{0}']), - ('\u{10ceb}', ['\u{10cab}', '\u{0}', '\u{0}']), - ('\u{10cec}', ['\u{10cac}', '\u{0}', '\u{0}']), - ('\u{10ced}', ['\u{10cad}', '\u{0}', '\u{0}']), - ('\u{10cee}', ['\u{10cae}', '\u{0}', '\u{0}']), - ('\u{10cef}', ['\u{10caf}', '\u{0}', '\u{0}']), - ('\u{10cf0}', ['\u{10cb0}', '\u{0}', '\u{0}']), - ('\u{10cf1}', ['\u{10cb1}', '\u{0}', '\u{0}']), - ('\u{10cf2}', ['\u{10cb2}', '\u{0}', '\u{0}']), - ('\u{118c0}', ['\u{118a0}', '\u{0}', '\u{0}']), - ('\u{118c1}', ['\u{118a1}', '\u{0}', '\u{0}']), - ('\u{118c2}', ['\u{118a2}', '\u{0}', '\u{0}']), - ('\u{118c3}', ['\u{118a3}', '\u{0}', '\u{0}']), - ('\u{118c4}', ['\u{118a4}', '\u{0}', '\u{0}']), - ('\u{118c5}', ['\u{118a5}', '\u{0}', '\u{0}']), - ('\u{118c6}', ['\u{118a6}', '\u{0}', '\u{0}']), - ('\u{118c7}', ['\u{118a7}', '\u{0}', '\u{0}']), - ('\u{118c8}', ['\u{118a8}', '\u{0}', '\u{0}']), - ('\u{118c9}', ['\u{118a9}', '\u{0}', '\u{0}']), - ('\u{118ca}', ['\u{118aa}', '\u{0}', '\u{0}']), - ('\u{118cb}', ['\u{118ab}', '\u{0}', '\u{0}']), - ('\u{118cc}', ['\u{118ac}', '\u{0}', '\u{0}']), - ('\u{118cd}', ['\u{118ad}', '\u{0}', '\u{0}']), - ('\u{118ce}', ['\u{118ae}', '\u{0}', '\u{0}']), - ('\u{118cf}', ['\u{118af}', '\u{0}', '\u{0}']), - ('\u{118d0}', ['\u{118b0}', '\u{0}', '\u{0}']), - ('\u{118d1}', ['\u{118b1}', '\u{0}', '\u{0}']), - ('\u{118d2}', ['\u{118b2}', '\u{0}', '\u{0}']), - ('\u{118d3}', ['\u{118b3}', '\u{0}', '\u{0}']), - ('\u{118d4}', ['\u{118b4}', '\u{0}', '\u{0}']), - ('\u{118d5}', ['\u{118b5}', '\u{0}', '\u{0}']), - ('\u{118d6}', ['\u{118b6}', '\u{0}', '\u{0}']), - ('\u{118d7}', ['\u{118b7}', '\u{0}', '\u{0}']), - ('\u{118d8}', ['\u{118b8}', '\u{0}', '\u{0}']), - ('\u{118d9}', ['\u{118b9}', '\u{0}', '\u{0}']), - ('\u{118da}', ['\u{118ba}', '\u{0}', '\u{0}']), - ('\u{118db}', ['\u{118bb}', '\u{0}', '\u{0}']), - ('\u{118dc}', ['\u{118bc}', '\u{0}', '\u{0}']), - ('\u{118dd}', ['\u{118bd}', '\u{0}', '\u{0}']), - ('\u{118de}', ['\u{118be}', '\u{0}', '\u{0}']), - ('\u{118df}', ['\u{118bf}', '\u{0}', '\u{0}']), - ('\u{16e60}', ['\u{16e40}', '\u{0}', '\u{0}']), - ('\u{16e61}', ['\u{16e41}', '\u{0}', '\u{0}']), - ('\u{16e62}', ['\u{16e42}', '\u{0}', '\u{0}']), - ('\u{16e63}', ['\u{16e43}', '\u{0}', '\u{0}']), - ('\u{16e64}', ['\u{16e44}', '\u{0}', '\u{0}']), - ('\u{16e65}', ['\u{16e45}', '\u{0}', '\u{0}']), - ('\u{16e66}', ['\u{16e46}', '\u{0}', '\u{0}']), - ('\u{16e67}', ['\u{16e47}', '\u{0}', '\u{0}']), - ('\u{16e68}', ['\u{16e48}', '\u{0}', '\u{0}']), - ('\u{16e69}', ['\u{16e49}', '\u{0}', '\u{0}']), - ('\u{16e6a}', ['\u{16e4a}', '\u{0}', '\u{0}']), - ('\u{16e6b}', ['\u{16e4b}', '\u{0}', '\u{0}']), - ('\u{16e6c}', ['\u{16e4c}', '\u{0}', '\u{0}']), - ('\u{16e6d}', ['\u{16e4d}', '\u{0}', '\u{0}']), - ('\u{16e6e}', ['\u{16e4e}', '\u{0}', '\u{0}']), - ('\u{16e6f}', ['\u{16e4f}', '\u{0}', '\u{0}']), - ('\u{16e70}', ['\u{16e50}', '\u{0}', '\u{0}']), - ('\u{16e71}', ['\u{16e51}', '\u{0}', '\u{0}']), - ('\u{16e72}', ['\u{16e52}', '\u{0}', '\u{0}']), - ('\u{16e73}', ['\u{16e53}', '\u{0}', '\u{0}']), - ('\u{16e74}', ['\u{16e54}', '\u{0}', '\u{0}']), - ('\u{16e75}', ['\u{16e55}', '\u{0}', '\u{0}']), - ('\u{16e76}', ['\u{16e56}', '\u{0}', '\u{0}']), - ('\u{16e77}', ['\u{16e57}', '\u{0}', '\u{0}']), - ('\u{16e78}', ['\u{16e58}', '\u{0}', '\u{0}']), - ('\u{16e79}', ['\u{16e59}', '\u{0}', '\u{0}']), - ('\u{16e7a}', ['\u{16e5a}', '\u{0}', '\u{0}']), - ('\u{16e7b}', ['\u{16e5b}', '\u{0}', '\u{0}']), - ('\u{16e7c}', ['\u{16e5c}', '\u{0}', '\u{0}']), - ('\u{16e7d}', ['\u{16e5d}', '\u{0}', '\u{0}']), - ('\u{16e7e}', ['\u{16e5e}', '\u{0}', '\u{0}']), - ('\u{16e7f}', ['\u{16e5f}', '\u{0}', '\u{0}']), - ('\u{1e922}', ['\u{1e900}', '\u{0}', '\u{0}']), - ('\u{1e923}', ['\u{1e901}', '\u{0}', '\u{0}']), - ('\u{1e924}', ['\u{1e902}', '\u{0}', '\u{0}']), - ('\u{1e925}', ['\u{1e903}', '\u{0}', '\u{0}']), - ('\u{1e926}', ['\u{1e904}', '\u{0}', '\u{0}']), - ('\u{1e927}', ['\u{1e905}', '\u{0}', '\u{0}']), - ('\u{1e928}', ['\u{1e906}', '\u{0}', '\u{0}']), - ('\u{1e929}', ['\u{1e907}', '\u{0}', '\u{0}']), - ('\u{1e92a}', ['\u{1e908}', '\u{0}', '\u{0}']), - ('\u{1e92b}', ['\u{1e909}', '\u{0}', '\u{0}']), - ('\u{1e92c}', ['\u{1e90a}', '\u{0}', '\u{0}']), - ('\u{1e92d}', ['\u{1e90b}', '\u{0}', '\u{0}']), - ('\u{1e92e}', ['\u{1e90c}', '\u{0}', '\u{0}']), - ('\u{1e92f}', ['\u{1e90d}', '\u{0}', '\u{0}']), - ('\u{1e930}', ['\u{1e90e}', '\u{0}', '\u{0}']), - ('\u{1e931}', ['\u{1e90f}', '\u{0}', '\u{0}']), - ('\u{1e932}', ['\u{1e910}', '\u{0}', '\u{0}']), - ('\u{1e933}', ['\u{1e911}', '\u{0}', '\u{0}']), - ('\u{1e934}', ['\u{1e912}', '\u{0}', '\u{0}']), - ('\u{1e935}', ['\u{1e913}', '\u{0}', '\u{0}']), - ('\u{1e936}', ['\u{1e914}', '\u{0}', '\u{0}']), - ('\u{1e937}', ['\u{1e915}', '\u{0}', '\u{0}']), - ('\u{1e938}', ['\u{1e916}', '\u{0}', '\u{0}']), - ('\u{1e939}', ['\u{1e917}', '\u{0}', '\u{0}']), - ('\u{1e93a}', ['\u{1e918}', '\u{0}', '\u{0}']), - ('\u{1e93b}', ['\u{1e919}', '\u{0}', '\u{0}']), - ('\u{1e93c}', ['\u{1e91a}', '\u{0}', '\u{0}']), - ('\u{1e93d}', ['\u{1e91b}', '\u{0}', '\u{0}']), - ('\u{1e93e}', ['\u{1e91c}', '\u{0}', '\u{0}']), - ('\u{1e93f}', ['\u{1e91d}', '\u{0}', '\u{0}']), - ('\u{1e940}', ['\u{1e91e}', '\u{0}', '\u{0}']), - ('\u{1e941}', ['\u{1e91f}', '\u{0}', '\u{0}']), - ('\u{1e942}', ['\u{1e920}', '\u{0}', '\u{0}']), - ('\u{1e943}', ['\u{1e921}', '\u{0}', '\u{0}']), + static UPPERCASE_TABLE_MULTI: &[[char; 3]] = &[ + ['S', 'S', '\u{0}'], ['\u{2bc}', 'N', '\u{0}'], ['J', '\u{30c}', '\u{0}'], + ['\u{399}', '\u{308}', '\u{301}'], ['\u{3a5}', '\u{308}', '\u{301}'], + ['\u{535}', '\u{552}', '\u{0}'], ['H', '\u{331}', '\u{0}'], ['T', '\u{308}', '\u{0}'], + ['W', '\u{30a}', '\u{0}'], ['Y', '\u{30a}', '\u{0}'], ['A', '\u{2be}', '\u{0}'], + ['\u{3a5}', '\u{313}', '\u{0}'], ['\u{3a5}', '\u{313}', '\u{300}'], + ['\u{3a5}', '\u{313}', '\u{301}'], ['\u{3a5}', '\u{313}', '\u{342}'], + ['\u{1f08}', '\u{399}', '\u{0}'], ['\u{1f09}', '\u{399}', '\u{0}'], + ['\u{1f0a}', '\u{399}', '\u{0}'], ['\u{1f0b}', '\u{399}', '\u{0}'], + ['\u{1f0c}', '\u{399}', '\u{0}'], ['\u{1f0d}', '\u{399}', '\u{0}'], + ['\u{1f0e}', '\u{399}', '\u{0}'], ['\u{1f0f}', '\u{399}', '\u{0}'], + ['\u{1f08}', '\u{399}', '\u{0}'], ['\u{1f09}', '\u{399}', '\u{0}'], + ['\u{1f0a}', '\u{399}', '\u{0}'], ['\u{1f0b}', '\u{399}', '\u{0}'], + ['\u{1f0c}', '\u{399}', '\u{0}'], ['\u{1f0d}', '\u{399}', '\u{0}'], + ['\u{1f0e}', '\u{399}', '\u{0}'], ['\u{1f0f}', '\u{399}', '\u{0}'], + ['\u{1f28}', '\u{399}', '\u{0}'], ['\u{1f29}', '\u{399}', '\u{0}'], + ['\u{1f2a}', '\u{399}', '\u{0}'], ['\u{1f2b}', '\u{399}', '\u{0}'], + ['\u{1f2c}', '\u{399}', '\u{0}'], ['\u{1f2d}', '\u{399}', '\u{0}'], + ['\u{1f2e}', '\u{399}', '\u{0}'], ['\u{1f2f}', '\u{399}', '\u{0}'], + ['\u{1f28}', '\u{399}', '\u{0}'], ['\u{1f29}', '\u{399}', '\u{0}'], + ['\u{1f2a}', '\u{399}', '\u{0}'], ['\u{1f2b}', '\u{399}', '\u{0}'], + ['\u{1f2c}', '\u{399}', '\u{0}'], ['\u{1f2d}', '\u{399}', '\u{0}'], + ['\u{1f2e}', '\u{399}', '\u{0}'], ['\u{1f2f}', '\u{399}', '\u{0}'], + ['\u{1f68}', '\u{399}', '\u{0}'], ['\u{1f69}', '\u{399}', '\u{0}'], + ['\u{1f6a}', '\u{399}', '\u{0}'], ['\u{1f6b}', '\u{399}', '\u{0}'], + ['\u{1f6c}', '\u{399}', '\u{0}'], ['\u{1f6d}', '\u{399}', '\u{0}'], + ['\u{1f6e}', '\u{399}', '\u{0}'], ['\u{1f6f}', '\u{399}', '\u{0}'], + ['\u{1f68}', '\u{399}', '\u{0}'], ['\u{1f69}', '\u{399}', '\u{0}'], + ['\u{1f6a}', '\u{399}', '\u{0}'], ['\u{1f6b}', '\u{399}', '\u{0}'], + ['\u{1f6c}', '\u{399}', '\u{0}'], ['\u{1f6d}', '\u{399}', '\u{0}'], + ['\u{1f6e}', '\u{399}', '\u{0}'], ['\u{1f6f}', '\u{399}', '\u{0}'], + ['\u{1fba}', '\u{399}', '\u{0}'], ['\u{391}', '\u{399}', '\u{0}'], + ['\u{386}', '\u{399}', '\u{0}'], ['\u{391}', '\u{342}', '\u{0}'], + ['\u{391}', '\u{342}', '\u{399}'], ['\u{391}', '\u{399}', '\u{0}'], + ['\u{1fca}', '\u{399}', '\u{0}'], ['\u{397}', '\u{399}', '\u{0}'], + ['\u{389}', '\u{399}', '\u{0}'], ['\u{397}', '\u{342}', '\u{0}'], + ['\u{397}', '\u{342}', '\u{399}'], ['\u{397}', '\u{399}', '\u{0}'], + ['\u{399}', '\u{308}', '\u{300}'], ['\u{399}', '\u{308}', '\u{301}'], + ['\u{399}', '\u{342}', '\u{0}'], ['\u{399}', '\u{308}', '\u{342}'], + ['\u{3a5}', '\u{308}', '\u{300}'], ['\u{3a5}', '\u{308}', '\u{301}'], + ['\u{3a1}', '\u{313}', '\u{0}'], ['\u{3a5}', '\u{342}', '\u{0}'], + ['\u{3a5}', '\u{308}', '\u{342}'], ['\u{1ffa}', '\u{399}', '\u{0}'], + ['\u{3a9}', '\u{399}', '\u{0}'], ['\u{38f}', '\u{399}', '\u{0}'], + ['\u{3a9}', '\u{342}', '\u{0}'], ['\u{3a9}', '\u{342}', '\u{399}'], + ['\u{3a9}', '\u{399}', '\u{0}'], ['F', 'F', '\u{0}'], ['F', 'I', '\u{0}'], + ['F', 'L', '\u{0}'], ['F', 'F', 'I'], ['F', 'F', 'L'], ['S', 'T', '\u{0}'], + ['S', 'T', '\u{0}'], ['\u{544}', '\u{546}', '\u{0}'], ['\u{544}', '\u{535}', '\u{0}'], + ['\u{544}', '\u{53b}', '\u{0}'], ['\u{54e}', '\u{546}', '\u{0}'], + ['\u{544}', '\u{53d}', '\u{0}'], ]; } diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs index 61807635813..c1c80c46c78 100644 --- a/library/core/tests/fmt/mod.rs +++ b/library/core/tests/fmt/mod.rs @@ -22,11 +22,11 @@ fn test_pointer_formats_data_pointer() { #[test] fn test_estimated_capacity() { assert_eq!(format_args!("").estimated_capacity(), 0); - assert_eq!(format_args!("{}", "").estimated_capacity(), 0); + assert_eq!(format_args!("{}", {""}).estimated_capacity(), 0); assert_eq!(format_args!("Hello").estimated_capacity(), 5); - assert_eq!(format_args!("Hello, {}!", "").estimated_capacity(), 16); - assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0); - assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 32); + assert_eq!(format_args!("Hello, {}!", {""}).estimated_capacity(), 16); + assert_eq!(format_args!("{}, hello!", {"World"}).estimated_capacity(), 0); + assert_eq!(format_args!("{}. 16-bytes piece", {"World"}).estimated_capacity(), 32); } #[test] diff --git a/library/core/tests/iter/consts.rs b/library/core/tests/iter/consts.rs new file mode 100644 index 00000000000..d56687e48c9 --- /dev/null +++ b/library/core/tests/iter/consts.rs @@ -0,0 +1,36 @@ +#[test] +fn const_manual_iter() { + struct S(bool); + + impl const Iterator for S { + type Item = (); + + fn next(&mut self) -> Option<Self::Item> { + if self.0 == false { + self.0 = true; + Some(()) + } else { + None + } + } + } + const { + let mut val = S(false); + assert!(val.next().is_some()); + assert!(val.next().is_none()); + assert!(val.next().is_none()); + } +} + +#[test] +fn const_range() { + const { + let mut arr = [0; 3]; + for i in 0..arr.len() { + arr[i] = i; + } + assert!(arr[0] == 0); + assert!(arr[1] == 1); + assert!(arr[2] == 2); + } +} diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs index 770b6f7601f..cbb18e79e2d 100644 --- a/library/core/tests/iter/mod.rs +++ b/library/core/tests/iter/mod.rs @@ -20,6 +20,8 @@ mod range; mod sources; mod traits; +mod consts; + use core::cell::Cell; use core::convert::TryFrom; use core::iter::*; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index ccb7be68eb1..637cc6e9f62 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -12,8 +12,11 @@ #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_convert)] +#![feature(const_for)] #![feature(const_hash)] #![feature(const_heap)] +#![feature(const_intoiterator_identity)] +#![feature(const_iter)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index b59f89d321c..837a18bff60 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -12,13 +12,6 @@ use crate::ops::{BitAnd, BitOr, BitXor, Sub}; use super::map::{map_try_reserve_error, RandomState}; -// Future Optimization (FIXME!) -// ============================ -// -// Iteration over zero sized values is a noop. There is no need -// for `bucket.val` in the case of HashSet. I suppose we would need HKT -// to get rid of it properly. - /// A [hash set] implemented as a `HashMap` where the value is `()`. /// /// As with the [`HashMap`] type, a `HashSet` requires that the elements diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 909d9bf4093..401def18458 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -2,7 +2,8 @@ use crate::io::prelude::*; use crate::env; use crate::fs::{self, File, OpenOptions}; -use crate::io::{ErrorKind, SeekFrom}; +use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; +use crate::mem::MaybeUninit; use crate::path::Path; use crate::str; use crate::sync::Arc; @@ -402,6 +403,23 @@ fn file_test_io_seek_read_write() { } #[test] +fn file_test_read_buf() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("test"); + check!(fs::write(filename, &[1, 2, 3, 4])); + + let mut buf: [MaybeUninit<u8>; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + let mut file = check!(File::open(filename)); + check!(file.read_buf(buf.unfilled())); + assert_eq!(buf.filled(), &[1, 2, 3, 4]); + // File::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); + + check!(fs::remove_file(filename)); +} + +#[test] fn file_test_stat_is_correct_on_is_file() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 7f07e4fddef..1cedd6eedfa 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -370,7 +370,7 @@ pub enum ErrorKind { // "Unusual" error kinds which do not correspond simply to (sets // of) OS error codes, should be added just above this comment. - // `Other` and `Uncategorised` should remain at the end: + // `Other` and `Uncategorized` should remain at the end: // /// A custom error that does not fall under any other I/O error kind. /// @@ -882,6 +882,13 @@ impl Error { /// Returns the corresponding [`ErrorKind`] for this error. /// + /// This may be a value set by Rust code constructing custom `io::Error`s, + /// or if this `io::Error` was sourced from the operating system, + /// it will be a value inferred from the system's error encoding. + /// See [`last_os_error`] for more details. + /// + /// [`last_os_error`]: Error::last_os_error + /// /// # Examples /// /// ``` @@ -892,7 +899,8 @@ impl Error { /// } /// /// fn main() { - /// // Will print "Uncategorized". + /// // As no error has (visibly) occurred, this may print anything! + /// // It likely prints a placeholder for unidentified (non-)errors. /// print_error(Error::last_os_error()); /// // Will print "AddrInUse". /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index b2b6d86134b..4b31c552eed 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -823,8 +823,22 @@ pub trait Read { /// Read the exact number of bytes required to fill `cursor`. /// - /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to - /// allow use with uninitialized buffers. + /// This is similar to the [`read_exact`](Read::read_exact) method, except + /// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use + /// with uninitialized buffers. + /// + /// # 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`]. + /// + /// If any other read error is encountered then this function immediately + /// returns. + /// + /// If this function returns an error, all bytes read will be appended to `cursor`. #[unstable(feature = "read_buf", issue = "78485")] fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> { while cursor.capacity() > 0 { diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 14bfef4c7aa..0455a00956e 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,7 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::fs::File; -use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; +use crate::io::{self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard}; use crate::sys::stdio; @@ -97,6 +97,10 @@ impl Read for StdinRaw { handle_ebadf(self.0.read(buf), 0) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + handle_ebadf(self.0.read_buf(buf), ()) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { handle_ebadf(self.0.read_vectored(bufs), 0) } @@ -418,6 +422,9 @@ impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.lock().read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.lock().read_buf(buf) + } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.lock().read_vectored(bufs) } @@ -450,6 +457,10 @@ impl Read for StdinLock<'_> { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.inner.read_vectored(bufs) } diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index ac09a805975..3982d363661 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -6,7 +6,7 @@ mod tests; use crate::io::prelude::*; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::iter::FusedIterator; use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; use crate::sys_common::net as net_imp; @@ -619,6 +619,10 @@ impl Read for TcpStream { self.0.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.0.read_vectored(bufs) } @@ -653,6 +657,10 @@ impl Read for &TcpStream { self.0.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.0.read_vectored(bufs) } diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index e019bc0b67a..7a3c66e4504 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -1,6 +1,7 @@ use crate::fmt; use crate::io::prelude::*; -use crate::io::{ErrorKind, IoSlice, IoSliceMut}; +use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut}; +use crate::mem::MaybeUninit; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; @@ -280,6 +281,31 @@ fn partial_read() { } #[test] +fn read_buf() { + each_ip(&mut |addr| { + let srv = t!(TcpListener::bind(&addr)); + let t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + s.write_all(&[1, 2, 3, 4]).unwrap(); + }); + + let mut s = t!(srv.accept()).0; + let mut buf: [MaybeUninit<u8>; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + t!(s.read_buf(buf.unfilled())); + assert_eq!(buf.filled(), &[1, 2, 3, 4]); + + // FIXME: sgx uses default_read_buf that initializes the buffer. + if cfg!(not(target_env = "sgx")) { + // TcpStream::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); + } + + t.join().ok().expect("thread panicked"); + }) +} + +#[test] fn read_vectored() { each_ip(&mut |addr| { let srv = t!(TcpListener::bind(&addr)); diff --git a/library/std/src/os/android/net.rs b/library/std/src/os/android/net.rs index 7cecd1bbfaa..4e88ab8ff5c 100644 --- a/library/std/src/os/android/net.rs +++ b/library/std/src/os/android/net.rs @@ -1,8 +1,8 @@ //! Android-specific networking functionality. -#![unstable(feature = "tcp_quickack", issue = "96256")] +#![stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub use crate::os::net::linux_ext::addr::SocketAddrExt; #[unstable(feature = "tcp_quickack", issue = "96256")] diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 258919d53a4..99a4e0b5106 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -399,7 +399,7 @@ impl<T: AsFd> AsFd for crate::sync::Arc<T> { } } -#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "asfd_rc", since = "1.69.0")] impl<T: AsFd> AsFd for crate::rc::Rc<T> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 0a4cefd2095..592e072ad90 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -254,7 +254,7 @@ impl<T: AsRawFd> AsRawFd for crate::sync::Arc<T> { } } -#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "asfd_rc", since = "1.69.0")] impl<T: AsRawFd> AsRawFd for crate::rc::Rc<T> { #[inline] fn as_raw_fd(&self) -> RawFd { diff --git a/library/std/src/os/linux/net.rs b/library/std/src/os/linux/net.rs index 94081c8dd31..fcb3bb83485 100644 --- a/library/std/src/os/linux/net.rs +++ b/library/std/src/os/linux/net.rs @@ -1,8 +1,8 @@ //! Linux-specific networking functionality. -#![unstable(feature = "tcp_quickack", issue = "96256")] +#![stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub use crate::os::net::linux_ext::addr::SocketAddrExt; #[unstable(feature = "tcp_quickack", issue = "96256")] diff --git a/library/std/src/os/net/linux_ext/addr.rs b/library/std/src/os/net/linux_ext/addr.rs index 85065984fbb..ea8102c9cc0 100644 --- a/library/std/src/os/net/linux_ext/addr.rs +++ b/library/std/src/os/net/linux_ext/addr.rs @@ -4,7 +4,7 @@ use crate::os::unix::net::SocketAddr; use crate::sealed::Sealed; /// Platform-specific extensions to [`SocketAddr`]. -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub trait SocketAddrExt: Sealed { /// Creates a Unix socket address in the abstract namespace. /// @@ -22,7 +22,6 @@ pub trait SocketAddrExt: Sealed { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixListener, SocketAddr}; /// use std::os::linux::net::SocketAddrExt; /// @@ -38,6 +37,7 @@ pub trait SocketAddrExt: Sealed { /// Ok(()) /// } /// ``` + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] fn from_abstract_name<N>(name: N) -> crate::io::Result<SocketAddr> where N: AsRef<[u8]>; @@ -47,7 +47,6 @@ pub trait SocketAddrExt: Sealed { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixListener, SocketAddr}; /// use std::os::linux::net::SocketAddrExt; /// @@ -60,5 +59,6 @@ pub trait SocketAddrExt: Sealed { /// Ok(()) /// } /// ``` + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] fn as_abstract_name(&self) -> Option<&[u8]>; } diff --git a/library/std/src/os/net/linux_ext/mod.rs b/library/std/src/os/net/linux_ext/mod.rs index 318ebacfd7a..e7423dce613 100644 --- a/library/std/src/os/net/linux_ext/mod.rs +++ b/library/std/src/os/net/linux_ext/mod.rs @@ -2,7 +2,7 @@ #![doc(cfg(any(target_os = "linux", target_os = "android")))] -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub(crate) mod addr; #[unstable(feature = "tcp_quickack", issue = "96256")] diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index ece2b33bddf..52a0da5bf1a 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -245,12 +245,12 @@ impl SocketAddr { } } -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] impl Sealed for SocketAddr {} #[doc(cfg(any(target_os = "android", target_os = "linux")))] #[cfg(any(doc, target_os = "android", target_os = "linux"))] -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] impl linux_ext::addr::SocketAddrExt for SocketAddr { fn as_abstract_name(&self) -> Option<&[u8]> { if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 272b4f5dcd5..e64569758a0 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -102,7 +102,6 @@ impl UnixDatagram { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { @@ -119,7 +118,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> { unsafe { let socket = UnixDatagram::unbound()?; @@ -217,7 +216,6 @@ impl UnixDatagram { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { @@ -235,7 +233,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { unsafe { cvt(libc::connect( @@ -523,7 +521,6 @@ impl UnixDatagram { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { @@ -535,7 +532,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result<usize> { unsafe { let count = cvt(libc::sendto( diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 02090afc82f..83f0debe676 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -90,7 +90,6 @@ impl UnixListener { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixListener}; /// /// fn main() -> std::io::Result<()> { @@ -107,7 +106,7 @@ impl UnixListener { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index dff8f6e8567..65cb4ae07a5 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -106,7 +106,6 @@ impl UnixStream { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixListener, UnixStream}; /// /// fn main() -> std::io::Result<()> { @@ -123,7 +122,7 @@ impl UnixStream { /// Ok(()) /// } /// ```` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result<UnixStream> { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 9fa8f5702a8..345d72ef867 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -308,8 +308,7 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> { BacktraceStyle::Short } }) - .unwrap_or(if cfg!(target_os = "fuchsia") { - // Fuchsia components default to full backtrace. + .unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT { BacktraceStyle::Full } else { BacktraceStyle::Off diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 6f78811a186..e12a3e378a6 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1110,7 +1110,7 @@ impl<T: Copy> Copy for (T,) { /// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected /// behavior: -/// - It is unequal to any float, including itself! This is the reason `f32` +/// - It is not equal to any float, including itself! This is the reason `f32` /// doesn't implement the `Eq` trait. /// - It is also neither smaller nor greater than any float, making it /// impossible to sort by the default comparison operation, which is the diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 1952e19e607..80d73084c4f 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -110,7 +110,7 @@ use crate::convert::Infallible; use crate::ffi::OsStr; use crate::fmt; use crate::fs; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::num::NonZeroI32; use crate::path::Path; use crate::str; @@ -354,6 +354,10 @@ impl Read for ChildStdout { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.inner.read_vectored(bufs) } @@ -419,6 +423,10 @@ impl Read for ChildStderr { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.inner.read_vectored(bufs) } diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index b4f6cc2daba..d7f4d335de3 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -1,7 +1,8 @@ use crate::io::prelude::*; use super::{Command, Output, Stdio}; -use crate::io::ErrorKind; +use crate::io::{BorrowedBuf, ErrorKind}; +use crate::mem::MaybeUninit; use crate::str; fn known_command() -> Command { @@ -121,6 +122,37 @@ fn stdin_works() { #[test] #[cfg_attr(any(target_os = "vxworks"), ignore)] +fn child_stdout_read_buf() { + let mut cmd = if cfg!(target_os = "windows") { + let mut cmd = Command::new("cmd"); + cmd.arg("/C").arg("echo abc"); + cmd + } else { + let mut cmd = shell_cmd(); + cmd.arg("-c").arg("echo abc"); + cmd + }; + cmd.stdin(Stdio::null()); + cmd.stdout(Stdio::piped()); + let child = cmd.spawn().unwrap(); + + let mut stdout = child.stdout.unwrap(); + let mut buf: [MaybeUninit<u8>; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + stdout.read_buf(buf.unfilled()).unwrap(); + + // ChildStdout::read_buf should omit buffer initialization. + if cfg!(target_os = "windows") { + assert_eq!(buf.filled(), b"abc\r\n"); + assert_eq!(buf.init_len(), 5); + } else { + assert_eq!(buf.filled(), b"abc\n"); + assert_eq!(buf.init_len(), 4); + }; +} + +#[test] +#[cfg_attr(any(target_os = "vxworks"), ignore)] fn test_process_status() { let mut status = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index c6bb09b0417..492e21d9bdb 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -25,7 +25,8 @@ struct Slot<T> { /// The current stamp. stamp: AtomicUsize, - /// The message in this slot. + /// The message in this slot. Either read out in `read` or dropped through + /// `discard_all_messages`. msg: UnsafeCell<MaybeUninit<T>>, } @@ -439,14 +440,13 @@ impl<T> Channel<T> { Some(self.cap) } - /// Disconnects the channel and wakes up all blocked senders and receivers. + /// Disconnects senders and wakes up all blocked receivers. /// /// Returns `true` if this call disconnected the channel. - pub(crate) fn disconnect(&self) -> bool { + pub(crate) fn disconnect_senders(&self) -> bool { let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); if tail & self.mark_bit == 0 { - self.senders.disconnect(); self.receivers.disconnect(); true } else { @@ -454,6 +454,85 @@ impl<T> Channel<T> { } } + /// Disconnects receivers and wakes up all blocked senders. + /// + /// Returns `true` if this call disconnected the channel. + /// + /// # Safety + /// May only be called once upon dropping the last receiver. The + /// destruction of all other receivers must have been observed with acquire + /// ordering or stronger. + pub(crate) unsafe fn disconnect_receivers(&self) -> bool { + let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); + let disconnected = if tail & self.mark_bit == 0 { + self.senders.disconnect(); + true + } else { + false + }; + + self.discard_all_messages(tail); + disconnected + } + + /// Discards all messages. + /// + /// `tail` should be the current (and therefore last) value of `tail`. + /// + /// # Panicking + /// If a destructor panics, the remaining messages are leaked, matching the + /// behaviour of the unbounded channel. + /// + /// # Safety + /// This method must only be called when dropping the last receiver. The + /// destruction of all other receivers must have been observed with acquire + /// ordering or stronger. + unsafe fn discard_all_messages(&self, tail: usize) { + debug_assert!(self.is_disconnected()); + + // Only receivers modify `head`, so since we are the last one, + // this value will not change and will not be observed (since + // no new messages can be sent after disconnection). + let mut head = self.head.load(Ordering::Relaxed); + let tail = tail & !self.mark_bit; + + let backoff = Backoff::new(); + loop { + // Deconstruct the head. + let index = head & (self.mark_bit - 1); + let lap = head & !(self.one_lap - 1); + + // Inspect the corresponding slot. + debug_assert!(index < self.buffer.len()); + let slot = unsafe { self.buffer.get_unchecked(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the stamp is ahead of the head by 1, we may drop the message. + if head + 1 == stamp { + head = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + head + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + unsafe { + (*slot.msg.get()).assume_init_drop(); + } + // If the tail equals the head, that means the channel is empty. + } else if tail == head { + return; + // Otherwise, a sender is about to write into the slot, so we need + // to wait for it to update the stamp. + } else { + backoff.spin_heavy(); + } + } + } + /// Returns `true` if the channel is disconnected. pub(crate) fn is_disconnected(&self) -> bool { self.tail.load(Ordering::SeqCst) & self.mark_bit != 0 @@ -483,23 +562,3 @@ impl<T> Channel<T> { head.wrapping_add(self.one_lap) == tail & !self.mark_bit } } - -impl<T> Drop for Channel<T> { - fn drop(&mut self) { - // Get the index of the head. - let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1); - - // Loop over all slots that hold a message and drop them. - for i in 0..self.len() { - // Compute the index of the next slot holding a message. - let index = if hix + i < self.cap { hix + i } else { hix + i - self.cap }; - - unsafe { - debug_assert!(index < self.buffer.len()); - let slot = self.buffer.get_unchecked_mut(index); - let msg = &mut *slot.msg.get(); - msg.as_mut_ptr().drop_in_place(); - } - } - } -} diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 7a602cecd3b..2068dda393a 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -227,7 +227,7 @@ impl<T> Drop for Sender<T> { fn drop(&mut self) { unsafe { match &self.flavor { - SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()), + SenderFlavor::Array(chan) => chan.release(|c| c.disconnect_senders()), SenderFlavor::List(chan) => chan.release(|c| c.disconnect_senders()), SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()), } @@ -403,7 +403,7 @@ impl<T> Drop for Receiver<T> { fn drop(&mut self) { unsafe { match &self.flavor { - ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect_receivers()), ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect_receivers()), ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()), } diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs index 9d2f92ffc9b..632709fd98d 100644 --- a/library/std/src/sync/mpsc/sync_tests.rs +++ b/library/std/src/sync/mpsc/sync_tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::env; +use crate::rc::Rc; use crate::sync::mpmc::SendTimeoutError; use crate::thread; use crate::time::Duration; @@ -656,3 +657,15 @@ fn issue_15761() { repro() } } + +#[test] +fn drop_unreceived() { + let (tx, rx) = sync_channel::<Rc<()>>(1); + let msg = Rc::new(()); + let weak = Rc::downgrade(&msg); + assert!(tx.send(msg).is_ok()); + drop(rx); + // Messages should be dropped immediately when the last receiver is destroyed. + assert!(weak.upgrade().is_none()); + drop(tx); +} diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 065045f4420..b8fec6902a0 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -107,8 +107,8 @@ use crate::sys::locks as sys; /// *guard += 1; /// ``` /// -/// It is sometimes necessary to manually drop the mutex guard to unlock it -/// sooner than the end of the enclosing scope. +/// To unlock a mutex guard sooner than the end of the enclosing scope, +/// either create an inner scope or drop the guard manually. /// /// ``` /// use std::sync::{Arc, Mutex}; @@ -125,11 +125,18 @@ use crate::sys::locks as sys; /// let res_mutex_clone = Arc::clone(&res_mutex); /// /// threads.push(thread::spawn(move || { -/// let mut data = data_mutex_clone.lock().unwrap(); -/// // This is the result of some important and long-ish work. -/// let result = data.iter().fold(0, |acc, x| acc + x * 2); -/// data.push(result); -/// drop(data); +/// // Here we use a block to limit the lifetime of the lock guard. +/// let result = { +/// let mut data = data_mutex_clone.lock().unwrap(); +/// // This is the result of some important and long-ish work. +/// let result = data.iter().fold(0, |acc, x| acc + x * 2); +/// data.push(result); +/// result +/// // The mutex guard gets dropped here, together with any other values +/// // created in the critical section. +/// }; +/// // The guard created here is a temporary dropped at the end of the statement, i.e. +/// // the lock would not remain being held even if the thread did some additional work. /// *res_mutex_clone.lock().unwrap() += result; /// })); /// }); @@ -146,6 +153,8 @@ use crate::sys::locks as sys; /// // It's even more important here than in the threads because we `.join` the /// // threads after that. If we had not dropped the mutex guard, a thread could /// // be waiting forever for it, causing a deadlock. +/// // As in the threads, a block could have been used instead of calling the +/// // `drop` function. /// drop(data); /// // Here the mutex guard is not assigned to a variable and so, even if the /// // scope does not end after this line, the mutex is still released: there is @@ -160,6 +169,7 @@ use crate::sys::locks as sys; /// /// assert_eq!(*res_mutex.lock().unwrap(), 800); /// ``` +/// #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")] pub struct Mutex<T: ?Sized> { diff --git a/library/std/src/sync/remutex.rs b/library/std/src/sync/remutex.rs index 4c054da6471..519ec2c32bd 100644 --- a/library/std/src/sync/remutex.rs +++ b/library/std/src/sync/remutex.rs @@ -35,7 +35,7 @@ use crate::sys::locks as sys; /// `owner` can be checked by other threads that want to see if they already /// hold the lock, so needs to be atomic. If it compares equal, we're on the /// same thread that holds the mutex and memory access can use relaxed ordering -/// since we're not dealing with multiple threads. If it compares unequal, +/// since we're not dealing with multiple threads. If it's not equal, /// synchronization is left to the mutex, making relaxed memory ordering for /// the `owner` field fine in all cases. pub struct ReentrantMutex<T> { diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index c966f217757..cf0b271761f 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -202,7 +202,7 @@ impl OpenOptions { create: false, create_new: false, // system-specific - mode: 0x777, + mode: 0o777, } } diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index c080c176a2a..e767b2866cb 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -76,3 +76,12 @@ cfg_if::cfg_if! { pub mod c; } } + +cfg_if::cfg_if! { + // Fuchsia components default to full backtrace. + if #[cfg(target_os = "fuchsia")] { + pub const FULL_BACKTRACE_DEFAULT: bool = true; + } else { + pub const FULL_BACKTRACE_DEFAULT: bool = false; + } +} diff --git a/library/std/src/sys/sgx/fd.rs b/library/std/src/sys/sgx/fd.rs index e5dc5b5adaa..0c02a107691 100644 --- a/library/std/src/sys/sgx/fd.rs +++ b/library/std/src/sys/sgx/fd.rs @@ -1,7 +1,7 @@ use fortanix_sgx_abi::Fd; use super::abi::usercalls; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::sys::{AsInner, FromInner, IntoInner}; @@ -30,6 +30,10 @@ impl FileDesc { usercalls::read(self.fd, &mut [IoSliceMut::new(buf)]) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|b| self.read(b), buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { usercalls::read(self.fd, bufs) } diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs index 4c4cd7d1d1d..923be5eb944 100644 --- a/library/std/src/sys/sgx/net.rs +++ b/library/std/src/sys/sgx/net.rs @@ -1,6 +1,6 @@ use crate::error; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sync::Arc; use crate::sys::fd::FileDesc; @@ -144,6 +144,10 @@ impl TcpStream { self.inner.inner.read(buf) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.inner.read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.inner.inner.read_vectored(bufs) } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 9874af4d3e2..ce5c048f252 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -469,6 +469,15 @@ impl<'a> Read for &'a FileDesc { fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { (**self).read_buf(cursor) } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + (**self).read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } } impl AsInner<OwnedFd> for FileDesc { diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 8e05b618daa..f84240d268f 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -1,6 +1,6 @@ use crate::cmp; use crate::ffi::CStr; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; @@ -242,19 +242,35 @@ impl Socket { self.0.duplicate().map(Socket) } - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { let ret = cvt(unsafe { - libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + libc::recv( + self.as_raw_fd(), + buf.as_mut().as_mut_ptr() as *mut c_void, + buf.capacity(), + flags, + ) })?; - Ok(ret as usize) + unsafe { + buf.advance(ret as usize); + } + Ok(()) } pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, 0) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), 0)?; + Ok(buf.len()) } pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, MSG_PEEK) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), MSG_PEEK)?; + Ok(buf.len()) + } + + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.recv_with_flags(buf, 0) } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index a744d0ab640..dc17c9fac46 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; @@ -49,6 +49,10 @@ impl AnonPipe { self.0.read(buf) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.0.read_vectored(bufs) } diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index b3626c564e8..a26f20795a1 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::unix::io::FromRawFd; use crate::sys::fd::FileDesc; @@ -18,6 +18,10 @@ impl io::Read for Stdin { unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) } } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_buf(buf) } + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) } } diff --git a/library/std/src/sys/unsupported/net.rs b/library/std/src/sys/unsupported/net.rs index a5204a08453..bbc52703f96 100644 --- a/library/std/src/sys/unsupported/net.rs +++ b/library/std/src/sys/unsupported/net.rs @@ -1,5 +1,5 @@ use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::sys::unsupported; use crate::time::Duration; @@ -39,6 +39,10 @@ impl TcpStream { self.0 } + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.0 } diff --git a/library/std/src/sys/unsupported/pipe.rs b/library/std/src/sys/unsupported/pipe.rs index 0bba673b458..d7d8f297ae5 100644 --- a/library/std/src/sys/unsupported/pipe.rs +++ b/library/std/src/sys/unsupported/pipe.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; pub struct AnonPipe(!); @@ -7,6 +7,10 @@ impl AnonPipe { self.0 } + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.0 } diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 0b9c8e61db8..191db4b60f7 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] use super::err2io; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; @@ -46,6 +46,22 @@ impl WasiFd { unsafe { wasi::fd_read(self.as_raw_fd() as wasi::Fd, iovec(bufs)).map_err(err2io) } } + pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { + unsafe { + let bufs = [wasi::Iovec { + buf: buf.as_mut().as_mut_ptr() as *mut u8, + buf_len: buf.capacity(), + }]; + match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) { + Ok(n) => { + buf.advance(n); + Ok(()) + } + Err(e) => Err(err2io(e)), + } + } + } + pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { unsafe { wasi::fd_write(self.as_raw_fd() as wasi::Fd, ciovec(bufs)).map_err(err2io) } } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index d4866bbc32b..3a205267e34 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -441,7 +441,7 @@ impl File { } pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - crate::io::default_read_buf(|buf| self.read(buf), cursor) + self.fd.read_buf(cursor) } pub fn write(&self, buf: &[u8]) -> io::Result<usize> { diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index cf4ebba1a39..59d94a3686d 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -3,7 +3,7 @@ use super::err2io; use super::fd::WasiFd; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::unsupported; @@ -91,6 +91,10 @@ impl TcpStream { self.read_vectored(&mut [IoSliceMut::new(buf)]) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.socket().as_inner().read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.socket().as_inner().read(bufs) } diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index 30356fa8519..43c0cdb657e 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -11,10 +11,11 @@ use crate::fmt; use crate::io; use crate::num::NonZeroU16; use crate::os::windows::prelude::*; -use crate::path::PathBuf; -use crate::sys::c; +use crate::path::{Path, PathBuf}; +use crate::sys::path::get_long_path; use crate::sys::process::ensure_no_nuls; use crate::sys::windows::os::current_exe; +use crate::sys::{c, to_u16s}; use crate::sys_common::wstr::WStrUnits; use crate::vec; @@ -311,7 +312,7 @@ pub(crate) fn make_bat_command_line( /// Takes a path and tries to return a non-verbatim path. /// /// This is necessary because cmd.exe does not support verbatim paths. -pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> { +pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> { use crate::ptr; use crate::sys::windows::fill_utf16_buf; @@ -324,6 +325,8 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> { const N: u16 = b'N' as _; const C: u16 = b'C' as _; + let mut path = to_u16s(path)?; + // Early return if the path is too long to remove the verbatim prefix. const LEGACY_MAX_PATH: usize = 260; if path.len() > LEGACY_MAX_PATH { @@ -337,7 +340,13 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> { fill_utf16_buf( |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()), |full_path: &[u16]| { - if full_path == &path[4..path.len() - 1] { full_path.into() } else { path } + if full_path == &path[4..path.len() - 1] { + let mut path: Vec<u16> = full_path.into(); + path.push(0); + path + } else { + path + } }, ) }, @@ -350,7 +359,9 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> { |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()), |full_path: &[u16]| { if full_path == &path[6..path.len() - 1] { - full_path.into() + let mut path: Vec<u16> = full_path.into(); + path.push(0); + path } else { // Restore the 'C' in "UNC". path[6] = b'C' as u16; @@ -360,6 +371,6 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> { ) }, // For everything else, leave the path unchanged. - _ => Ok(path), + _ => get_long_path(path, false), } } diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 5d150eca00e..1f4092ad738 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -296,7 +296,6 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _; pub const STATUS_PENDING: NTSTATUS = 0x103 as _; pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _; -pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _; // Equivalent to the `NT_SUCCESS` C preprocessor macro. // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values @@ -1282,6 +1281,46 @@ extern "system" { ) -> NTSTATUS; } +#[link(name = "ntdll")] +extern "system" { + pub fn NtCreateFile( + FileHandle: *mut HANDLE, + DesiredAccess: ACCESS_MASK, + ObjectAttributes: *const OBJECT_ATTRIBUTES, + IoStatusBlock: *mut IO_STATUS_BLOCK, + AllocationSize: *mut i64, + FileAttributes: ULONG, + ShareAccess: ULONG, + CreateDisposition: ULONG, + CreateOptions: ULONG, + EaBuffer: *mut c_void, + EaLength: ULONG, + ) -> NTSTATUS; + pub fn NtReadFile( + FileHandle: BorrowedHandle<'_>, + Event: HANDLE, + ApcRoutine: Option<IO_APC_ROUTINE>, + ApcContext: *mut c_void, + IoStatusBlock: &mut IO_STATUS_BLOCK, + Buffer: *mut crate::mem::MaybeUninit<u8>, + Length: ULONG, + ByteOffset: Option<&LARGE_INTEGER>, + Key: Option<&ULONG>, + ) -> NTSTATUS; + pub fn NtWriteFile( + FileHandle: BorrowedHandle<'_>, + Event: HANDLE, + ApcRoutine: Option<IO_APC_ROUTINE>, + ApcContext: *mut c_void, + IoStatusBlock: &mut IO_STATUS_BLOCK, + Buffer: *const u8, + Length: ULONG, + ByteOffset: Option<&LARGE_INTEGER>, + Key: Option<&ULONG>, + ) -> NTSTATUS; + pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> ULONG; +} + // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn_with_fallback! { @@ -1322,52 +1361,6 @@ compat_fn_optional! { compat_fn_with_fallback! { pub static NTDLL: &CStr = ansi_str!("ntdll"); - pub fn NtCreateFile( - FileHandle: *mut HANDLE, - DesiredAccess: ACCESS_MASK, - ObjectAttributes: *const OBJECT_ATTRIBUTES, - IoStatusBlock: *mut IO_STATUS_BLOCK, - AllocationSize: *mut i64, - FileAttributes: ULONG, - ShareAccess: ULONG, - CreateDisposition: ULONG, - CreateOptions: ULONG, - EaBuffer: *mut c_void, - EaLength: ULONG - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - pub fn NtReadFile( - FileHandle: BorrowedHandle<'_>, - Event: HANDLE, - ApcRoutine: Option<IO_APC_ROUTINE>, - ApcContext: *mut c_void, - IoStatusBlock: &mut IO_STATUS_BLOCK, - Buffer: *mut crate::mem::MaybeUninit<u8>, - Length: ULONG, - ByteOffset: Option<&LARGE_INTEGER>, - Key: Option<&ULONG> - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - pub fn NtWriteFile( - FileHandle: BorrowedHandle<'_>, - Event: HANDLE, - ApcRoutine: Option<IO_APC_ROUTINE>, - ApcContext: *mut c_void, - IoStatusBlock: &mut IO_STATUS_BLOCK, - Buffer: *const u8, - Length: ULONG, - ByteOffset: Option<&LARGE_INTEGER>, - Key: Option<&ULONG> - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - pub fn RtlNtStatusToDosError( - Status: NTSTATUS - ) -> ULONG { - Status as ULONG - } pub fn NtCreateKeyedEvent( KeyedEventHandle: LPHANDLE, DesiredAccess: ACCESS_MASK, diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index d2c597664fa..373157bd9e8 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1236,7 +1236,17 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { } pub fn stat(path: &Path) -> io::Result<FileAttr> { - metadata(path, ReparsePoint::Follow) + match metadata(path, ReparsePoint::Follow) { + Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => { + if let Ok(attrs) = lstat(path) { + if !attrs.file_type().is_symlink() { + return Ok(attrs); + } + } + Err(err) + } + result => result, + } } pub fn lstat(path: &Path) -> io::Result<FileAttr> { diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index ae33d48c612..b290f4070e8 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -327,7 +327,16 @@ impl<'a> Read for &'a Handle { (**self).read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + (**self).read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { (**self).read_vectored(bufs) } + + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index e0701a498fa..ee1f5482b47 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -1,7 +1,7 @@ #![unstable(issue = "none", feature = "windows_net")] use crate::cmp; -use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ @@ -214,28 +214,38 @@ impl Socket { Ok(Self(self.0.try_clone()?)) } - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let length = cmp::min(buf.len(), i32::MAX as usize) as i32; - let result = - unsafe { c::recv(self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags) }; + let length = cmp::min(buf.capacity(), i32::MAX as usize) as i32; + let result = unsafe { + c::recv(self.as_raw_socket(), buf.as_mut().as_mut_ptr() as *mut _, length, flags) + }; match result { c::SOCKET_ERROR => { let error = unsafe { c::WSAGetLastError() }; if error == c::WSAESHUTDOWN { - Ok(0) + Ok(()) } else { Err(io::Error::from_raw_os_error(error)) } } - _ => Ok(result as usize), + _ => { + unsafe { buf.advance(result as usize) }; + Ok(()) + } } } pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), 0)?; + Ok(buf.len()) + } + + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { self.recv_with_flags(buf, 0) } @@ -277,7 +287,9 @@ impl Socket { } pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, c::MSG_PEEK) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), c::MSG_PEEK)?; + Ok(buf.len()) } fn recv_from_with_flags( diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index beeca1917a9..c3573d14c7f 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -220,6 +220,19 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { /// /// This path may or may not have a verbatim prefix. pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> { + let path = to_u16s(path)?; + get_long_path(path, true) +} + +/// Get a normalized absolute path that can bypass path length limits. +/// +/// Setting prefer_verbatim to true suggests a stronger preference for verbatim +/// paths even when not strictly necessary. This allows the Windows API to avoid +/// repeating our work. However, if the path may be given back to users or +/// passed to other application then it's preferable to use non-verbatim paths +/// when possible. Non-verbatim paths are better understood by users and handled +/// by more software. +pub(crate) fn get_long_path(mut path: Vec<u16>, prefer_verbatim: bool) -> io::Result<Vec<u16>> { // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL). // However, for APIs such as CreateDirectory[1], the limit is 248. // @@ -243,7 +256,6 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> { // \\?\UNC\ const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP]; - let mut path = to_u16s(path)?; if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) || path == &[0] { // Early return for paths that are already verbatim or empty. return Ok(path); @@ -275,29 +287,34 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> { |mut absolute| { path.clear(); - // Secondly, add the verbatim prefix. This is easier here because we know the - // path is now absolute and fully normalized (e.g. `/` has been changed to `\`). - let prefix = match absolute { - // C:\ => \\?\C:\ - [_, COLON, SEP, ..] => VERBATIM_PREFIX, - // \\.\ => \\?\ - [SEP, SEP, DOT, SEP, ..] => { - absolute = &absolute[4..]; - VERBATIM_PREFIX - } - // Leave \\?\ and \??\ as-is. - [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[], - // \\ => \\?\UNC\ - [SEP, SEP, ..] => { - absolute = &absolute[2..]; - UNC_PREFIX - } - // Anything else we leave alone. - _ => &[], - }; - - path.reserve_exact(prefix.len() + absolute.len() + 1); - path.extend_from_slice(prefix); + // Only prepend the prefix if needed. + if prefer_verbatim || absolute.len() + 1 >= LEGACY_MAX_PATH { + // Secondly, add the verbatim prefix. This is easier here because we know the + // path is now absolute and fully normalized (e.g. `/` has been changed to `\`). + let prefix = match absolute { + // C:\ => \\?\C:\ + [_, COLON, SEP, ..] => VERBATIM_PREFIX, + // \\.\ => \\?\ + [SEP, SEP, DOT, SEP, ..] => { + absolute = &absolute[4..]; + VERBATIM_PREFIX + } + // Leave \\?\ and \??\ as-is. + [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[], + // \\ => \\?\UNC\ + [SEP, SEP, ..] => { + absolute = &absolute[2..]; + UNC_PREFIX + } + // Anything else we leave alone. + _ => &[], + }; + + path.reserve_exact(prefix.len() + absolute.len() + 1); + path.extend_from_slice(prefix); + } else { + path.reserve_exact(absolute.len() + 1); + } path.extend_from_slice(absolute); path.push(0); }, diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs index 7b25edaa556..0780b29584d 100644 --- a/library/std/src/sys/windows/pipe.rs +++ b/library/std/src/sys/windows/pipe.rs @@ -1,7 +1,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsStr; -use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::path::Path; use crate::ptr; @@ -252,6 +252,28 @@ impl AnonPipe { } } + pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { + let result = unsafe { + let len = crate::cmp::min(buf.capacity(), c::DWORD::MAX as usize) as c::DWORD; + self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len) + }; + + match result { + // The special treatment of BrokenPipe is to deal with Windows + // pipe semantics, which yields this error when *reading* from + // a pipe after the other end has closed; we interpret that as + // EOF on the pipe. + Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()), + Err(e) => Err(e), + Ok(n) => { + unsafe { + buf.advance(n); + } + Ok(()) + } + } + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.inner.read_vectored(bufs) } diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 10bc949e1f4..1c73b64e250 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -266,11 +266,7 @@ impl Command { let (program, mut cmd_str) = if is_batch_file { ( command_prompt()?, - args::make_bat_command_line( - &args::to_user_path(program)?, - &self.args, - self.force_quotes_enabled, - )?, + args::make_bat_command_line(&program, &self.args, self.force_quotes_enabled)?, ) } else { let cmd_str = make_command_line(&self.program, &self.args, self.force_quotes_enabled)?; @@ -410,7 +406,7 @@ fn resolve_exe<'a>( if has_exe_suffix { // The application name is a path to a `.exe` file. // Let `CreateProcessW` figure out if it exists or not. - return path::maybe_verbatim(Path::new(exe_path)); + return args::to_user_path(Path::new(exe_path)); } let mut path = PathBuf::from(exe_path); @@ -422,7 +418,7 @@ fn resolve_exe<'a>( // It's ok to use `set_extension` here because the intent is to // remove the extension that was just added. path.set_extension(""); - return path::maybe_verbatim(&path); + return args::to_user_path(&path); } } else { ensure_no_nuls(exe_path)?; @@ -510,7 +506,7 @@ where /// Check if a file exists without following symlinks. fn program_exists(path: &Path) -> Option<Vec<u16>> { unsafe { - let path = path::maybe_verbatim(path).ok()?; + let path = args::to_user_path(path).ok()?; // Getting attributes using `GetFileAttributesW` does not follow symlinks // and it will almost always be successful if the link exists. // There are some exceptions for special system files (e.g. the pagefile) diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 85ecc1def3a..eb427dbda23 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -4,7 +4,7 @@ mod tests; use crate::cmp; use crate::convert::{TryFrom, TryInto}; use crate::fmt; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::ptr; @@ -272,6 +272,10 @@ impl TcpStream { self.inner.read(buf) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.inner.read_vectored(bufs) } diff --git a/library/stdarch b/library/stdarch -Subproject a0c30f3e3c75adcd6ee7efc94014ebcead61c50 +Subproject b655243782c18d3419439daa523782e0818ecf2 diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 1ee68c8540b..7eee4ca2361 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -41,6 +41,46 @@ impl<T: Write> Write for OutputLocation<T> { } } +pub struct ConsoleTestDiscoveryState { + pub log_out: Option<File>, + pub tests: usize, + pub benchmarks: usize, + pub ignored: usize, + pub options: Options, +} + +impl ConsoleTestDiscoveryState { + pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestDiscoveryState> { + let log_out = match opts.logfile { + Some(ref path) => Some(File::create(path)?), + None => None, + }; + + Ok(ConsoleTestDiscoveryState { + log_out, + tests: 0, + benchmarks: 0, + ignored: 0, + options: opts.options, + }) + } + + pub fn write_log<F, S>(&mut self, msg: F) -> io::Result<()> + where + S: AsRef<str>, + F: FnOnce() -> S, + { + match self.log_out { + None => Ok(()), + Some(ref mut o) => { + let msg = msg(); + let msg = msg.as_ref(); + o.write_all(msg.as_bytes()) + } + } + } +} + pub struct ConsoleTestState { pub log_out: Option<File>, pub total: usize, @@ -138,53 +178,44 @@ impl ConsoleTestState { // List the tests to console, and optionally to logfile. Filters are honored. pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> { - let mut output = match term::stdout() { + let output = match term::stdout() { None => OutputLocation::Raw(io::stdout().lock()), Some(t) => OutputLocation::Pretty(t), }; - let quiet = opts.format == OutputFormat::Terse; - let mut st = ConsoleTestState::new(opts)?; - - let mut ntest = 0; - let mut nbench = 0; + let mut out: Box<dyn OutputFormatter> = match opts.format { + OutputFormat::Pretty | OutputFormat::Junit => { + Box::new(PrettyFormatter::new(output, false, 0, false, None)) + } + OutputFormat::Terse => Box::new(TerseFormatter::new(output, false, 0, false)), + OutputFormat::Json => Box::new(JsonFormatter::new(output)), + }; + let mut st = ConsoleTestDiscoveryState::new(opts)?; + out.write_discovery_start()?; for test in filter_tests(opts, tests).into_iter() { use crate::TestFn::*; - let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test; + let TestDescAndFn { desc, testfn } = test; let fntype = match testfn { StaticTestFn(..) | DynTestFn(..) => { - ntest += 1; + st.tests += 1; "test" } StaticBenchFn(..) | DynBenchFn(..) => { - nbench += 1; + st.benchmarks += 1; "benchmark" } }; - writeln!(output, "{name}: {fntype}")?; - st.write_log(|| format!("{fntype} {name}\n"))?; - } + st.ignored += if desc.ignore { 1 } else { 0 }; - fn plural(count: u32, s: &str) -> String { - match count { - 1 => format!("1 {s}"), - n => format!("{n} {s}s"), - } + out.write_test_discovered(&desc, fntype)?; + st.write_log(|| format!("{fntype} {}\n", desc.name))?; } - if !quiet { - if ntest != 0 || nbench != 0 { - writeln!(output)?; - } - - writeln!(output, "{}, {}", plural(ntest, "test"), plural(nbench, "benchmark"))?; - } - - Ok(()) + out.write_discovery_finish(&st) } // Updates `ConsoleTestState` depending on result of the test execution. diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs index 95d2faf2506..40976ec5e1c 100644 --- a/library/test/src/formatters/json.rs +++ b/library/test/src/formatters/json.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, io, io::prelude::Write}; use super::OutputFormatter; use crate::{ - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, test_result::TestResult, time, types::TestDesc, @@ -60,6 +60,56 @@ impl<T: Write> JsonFormatter<T> { } impl<T: Write> OutputFormatter for JsonFormatter<T> { + fn write_discovery_start(&mut self) -> io::Result<()> { + self.writeln_message(&format!(r#"{{ "type": "suite", "event": "discovery" }}"#)) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + let TestDesc { + name, + ignore, + ignore_message, + #[cfg(not(bootstrap))] + source_file, + #[cfg(not(bootstrap))] + start_line, + #[cfg(not(bootstrap))] + start_col, + #[cfg(not(bootstrap))] + end_line, + #[cfg(not(bootstrap))] + end_col, + .. + } = desc; + + #[cfg(bootstrap)] + let source_file = ""; + #[cfg(bootstrap)] + let start_line = 0; + #[cfg(bootstrap)] + let start_col = 0; + #[cfg(bootstrap)] + let end_line = 0; + #[cfg(bootstrap)] + let end_col = 0; + + self.writeln_message(&format!( + r#"{{ "type": "{test_type}", "event": "discovered", "name": "{}", "ignore": {ignore}, "ignore_message": "{}", "source_path": "{}", "start_line": {start_line}, "start_col": {start_col}, "end_line": {end_line}, "end_col": {end_col} }}"#, + EscapedString(name.as_slice()), + ignore_message.unwrap_or(""), + EscapedString(source_file), + )) + } + + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> { + let ConsoleTestDiscoveryState { tests, benchmarks, ignored, .. } = state; + + let total = tests + benchmarks; + self.writeln_message(&format!( + r#"{{ "type": "suite", "event": "completed", "tests": {tests}, "benchmarks": {benchmarks}, "total": {total}, "ignored": {ignored} }}"# + )) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> { let shuffle_seed_json = if let Some(shuffle_seed) = shuffle_seed { format!(r#", "shuffle_seed": {shuffle_seed}"#) diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index 7a40ce33cb7..2e07ce3c099 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -3,7 +3,7 @@ use std::time::Duration; use super::OutputFormatter; use crate::{ - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, test_result::TestResult, time, types::{TestDesc, TestType}, @@ -27,6 +27,18 @@ impl<T: Write> JunitFormatter<T> { } impl<T: Write> OutputFormatter for JunitFormatter<T> { + fn write_discovery_start(&mut self) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + + fn write_test_discovered(&mut self, _desc: &TestDesc, _test_type: &str) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + + fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + fn write_run_start( &mut self, _test_count: usize, diff --git a/library/test/src/formatters/mod.rs b/library/test/src/formatters/mod.rs index cb67b6491a3..bc6ffebc1d3 100644 --- a/library/test/src/formatters/mod.rs +++ b/library/test/src/formatters/mod.rs @@ -1,7 +1,7 @@ use std::{io, io::prelude::Write}; use crate::{ - console::ConsoleTestState, + console::{ConsoleTestDiscoveryState, ConsoleTestState}, test_result::TestResult, time, types::{TestDesc, TestName}, @@ -18,6 +18,10 @@ pub(crate) use self::pretty::PrettyFormatter; pub(crate) use self::terse::TerseFormatter; pub(crate) trait OutputFormatter { + fn write_discovery_start(&mut self) -> io::Result<()>; + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()>; + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()>; + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()>; fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>; fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 247778e515f..22654a3400b 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -3,7 +3,7 @@ use std::{io, io::prelude::Write}; use super::OutputFormatter; use crate::{ bench::fmt_bench_samples, - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, term, test_result::TestResult, time, @@ -181,6 +181,33 @@ impl<T: Write> PrettyFormatter<T> { } impl<T: Write> OutputFormatter for PrettyFormatter<T> { + fn write_discovery_start(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + self.write_plain(format!("{}: {test_type}\n", desc.name)) + } + + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> { + fn plural(count: usize, s: &str) -> String { + match count { + 1 => format!("1 {s}"), + n => format!("{n} {s}s"), + } + } + + if state.tests != 0 || state.benchmarks != 0 { + self.write_plain("\n")?; + } + + self.write_plain(format!( + "{}, {}\n", + plural(state.tests, "test"), + plural(state.benchmarks, "benchmark") + )) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> { let noun = if test_count != 1 { "tests" } else { "test" }; let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed { diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index a431acfbc27..2931ca6ead0 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -3,7 +3,7 @@ use std::{io, io::prelude::Write}; use super::OutputFormatter; use crate::{ bench::fmt_bench_samples, - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, term, test_result::TestResult, time, @@ -167,6 +167,18 @@ impl<T: Write> TerseFormatter<T> { } impl<T: Write> OutputFormatter for TerseFormatter<T> { + fn write_discovery_start(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + self.write_plain(format!("{}: {test_type}\n", desc.name)) + } + + fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> { + Ok(()) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> { self.total_test_count = test_count; let noun = if test_count != 1 { "tests" } else { "test" }; diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 44776fb0a31..5ffdbf73fbf 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -63,6 +63,16 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> { name: StaticTestName("1"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -75,6 +85,16 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> { name: StaticTestName("2"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -95,6 +115,16 @@ pub fn do_not_run_ignored_tests() { name: StaticTestName("whatever"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -118,6 +148,16 @@ pub fn ignored_tests_result_in_ignored() { name: StaticTestName("whatever"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -143,6 +183,16 @@ fn test_should_panic() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::Yes, compile_fail: false, no_run: false, @@ -168,6 +218,16 @@ fn test_should_panic_good_message() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage("error message"), compile_fail: false, no_run: false, @@ -198,6 +258,16 @@ fn test_should_panic_bad_message() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage(expected), compile_fail: false, no_run: false, @@ -232,6 +302,16 @@ fn test_should_panic_non_string_message_type() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage(expected), compile_fail: false, no_run: false, @@ -260,6 +340,16 @@ fn test_should_panic_but_succeeds() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic, compile_fail: false, no_run: false, @@ -288,6 +378,16 @@ fn report_time_test_template(report_time: bool) -> Option<TestExecTime> { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -325,6 +425,16 @@ fn time_test_failure_template(test_type: TestType) -> TestResult { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -364,6 +474,16 @@ fn typed_test_desc(test_type: TestType) -> TestDesc { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -476,6 +596,16 @@ pub fn exclude_should_panic_option() { name: StaticTestName("3"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::Yes, compile_fail: false, no_run: false, @@ -500,6 +630,16 @@ pub fn exact_filter_match() { name: StaticTestName(name), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -591,6 +731,16 @@ fn sample_tests() -> Vec<TestDescAndFn> { name: DynTestName((*name).clone()), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -720,6 +870,16 @@ pub fn test_bench_no_iter() { name: StaticTestName("f"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -743,6 +903,16 @@ pub fn test_bench_iter() { name: StaticTestName("f"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -759,6 +929,16 @@ fn should_sort_failures_before_printing_them() { name: StaticTestName("a"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -769,6 +949,16 @@ fn should_sort_failures_before_printing_them() { name: StaticTestName("b"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -816,6 +1006,16 @@ fn test_dyn_bench_returning_err_fails_when_run_as_test() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 6f2e033095a..8d4e204c8ac 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -119,6 +119,16 @@ pub struct TestDesc { pub name: TestName, pub ignore: bool, pub ignore_message: Option<&'static str>, + #[cfg(not(bootstrap))] + pub source_file: &'static str, + #[cfg(not(bootstrap))] + pub start_line: usize, + #[cfg(not(bootstrap))] + pub start_col: usize, + #[cfg(not(bootstrap))] + pub end_line: usize, + #[cfg(not(bootstrap))] + pub end_col: usize, pub should_panic: options::ShouldPanic, pub compile_fail: bool, pub no_run: bool, diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index e861d520c53..27236e191fd 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -12,6 +12,17 @@ dependencies = [ ] [[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -36,6 +47,7 @@ dependencies = [ name = "bootstrap" version = "0.0.0" dependencies = [ + "atty", "build_helper", "cc", "cmake", @@ -55,9 +67,10 @@ dependencies = [ "sha2", "sysinfo", "tar", + "termcolor", "toml", "walkdir", - "winapi", + "windows", "xz2", ] @@ -637,6 +650,15 @@ dependencies = [ ] [[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] name = "thread_local" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -721,6 +743,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets", +] + +[[package]] name = "windows-sys" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -736,46 +767,61 @@ dependencies = [ ] [[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "xattr" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index afe3fc1741b..5c659800bdb 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -30,6 +30,7 @@ path = "bin/sccache-plus-cl.rs" test = false [dependencies] +atty = "0.2.14" build_helper = { path = "../tools/build_helper" } cmake = "0.1.38" filetime = "0.2" @@ -45,6 +46,7 @@ serde_derive = "1.0.137" serde_json = "1.0.2" sha2 = "0.10" tar = "0.4" +termcolor = "1.2.0" toml = "0.5" ignore = "0.4.10" opener = "0.5" @@ -59,18 +61,20 @@ sysinfo = { version = "0.26.0", optional = true } [target.'cfg(not(target_os = "solaris"))'.dependencies] fd-lock = "3.0.8" -[target.'cfg(windows)'.dependencies.winapi] -version = "0.3" +[target.'cfg(windows)'.dependencies.windows] +version = "0.46.0" features = [ - "fileapi", - "ioapiset", - "jobapi2", - "handleapi", - "winioctl", - "psapi", - "impl-default", - "timezoneapi", - "winbase", + "Win32_Foundation", + "Win32_Security", + "Win32_Storage_FileSystem", + "Win32_System_Diagnostics_Debug", + "Win32_System_IO", + "Win32_System_Ioctl", + "Win32_System_JobObjects", + "Win32_System_ProcessStatus", + "Win32_System_SystemServices", + "Win32_System_Threading", + "Win32_System_Time", ] [dev-dependencies] diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 9611c866df5..040fec3615b 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -281,41 +281,49 @@ fn format_rusage_data(_child: Child) -> Option<String> { #[cfg(windows)] fn format_rusage_data(child: Child) -> Option<String> { use std::os::windows::io::AsRawHandle; - use winapi::um::{processthreadsapi, psapi, timezoneapi}; - let handle = child.as_raw_handle(); - macro_rules! try_bool { - ($e:expr) => { - if $e != 1 { - return None; - } - }; - } + + use windows::{ + Win32::Foundation::HANDLE, + Win32::System::ProcessStatus::{ + K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX, + }, + Win32::System::Threading::GetProcessTimes, + Win32::System::Time::FileTimeToSystemTime, + }; + + let handle = HANDLE(child.as_raw_handle() as isize); let mut user_filetime = Default::default(); let mut user_time = Default::default(); let mut kernel_filetime = Default::default(); let mut kernel_time = Default::default(); - let mut memory_counters = psapi::PROCESS_MEMORY_COUNTERS::default(); + let mut memory_counters = PROCESS_MEMORY_COUNTERS::default(); unsafe { - try_bool!(processthreadsapi::GetProcessTimes( + GetProcessTimes( handle, &mut Default::default(), &mut Default::default(), &mut kernel_filetime, &mut user_filetime, - )); - try_bool!(timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time)); - try_bool!(timezoneapi::FileTimeToSystemTime(&kernel_filetime, &mut kernel_time)); - - // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process - // with the given handle and none of that process's children. - try_bool!(psapi::GetProcessMemoryInfo( - handle as _, - &mut memory_counters as *mut _ as _, - std::mem::size_of::<psapi::PROCESS_MEMORY_COUNTERS_EX>() as u32, - )); + ) + } + .ok() + .ok()?; + unsafe { FileTimeToSystemTime(&user_filetime, &mut user_time) }.ok().ok()?; + unsafe { FileTimeToSystemTime(&kernel_filetime, &mut kernel_time) }.ok().ok()?; + + // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process + // with the given handle and none of that process's children. + unsafe { + K32GetProcessMemoryInfo( + handle, + &mut memory_counters, + std::mem::size_of::<PROCESS_MEMORY_COUNTERS_EX>() as u32, + ) } + .ok() + .ok()?; // Guide on interpreting these numbers: // https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py index 06ca3ce21b3..20bd71f06e9 100644 --- a/src/bootstrap/bootstrap_test.py +++ b/src/bootstrap/bootstrap_test.py @@ -11,6 +11,7 @@ import sys from shutil import rmtree import bootstrap +import configure class VerifyTestCase(unittest.TestCase): @@ -74,12 +75,50 @@ class ProgramOutOfDate(unittest.TestCase): self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key)) +class GenerateAndParseConfig(unittest.TestCase): + """Test that we can serialize and deserialize a config.toml file""" + def serialize_and_parse(self, args): + from io import StringIO + + section_order, sections, targets = configure.parse_args(args) + buffer = StringIO() + configure.write_config_toml(buffer, section_order, targets, sections) + build = bootstrap.RustBuild() + build.config_toml = buffer.getvalue() + + try: + import tomllib + # Verify this is actually valid TOML. + tomllib.loads(build.config_toml) + except ImportError: + print("warning: skipping TOML validation, need at least python 3.11", file=sys.stderr) + return build + + def test_no_args(self): + build = self.serialize_and_parse([]) + self.assertEqual(build.get_toml("changelog-seen"), '2') + self.assertIsNone(build.get_toml("llvm.download-ci-llvm")) + + def test_set_section(self): + build = self.serialize_and_parse(["--set", "llvm.download-ci-llvm"]) + self.assertEqual(build.get_toml("download-ci-llvm", section="llvm"), 'true') + + def test_set_target(self): + build = self.serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"]) + self.assertEqual(build.get_toml("cc", section="target.x86_64-unknown-linux-gnu"), 'gcc') + + # Uncomment when #108928 is fixed. + # def test_set_top_level(self): + # build = self.serialize_and_parse(["--set", "profile=compiler"]) + # self.assertEqual(build.get_toml("profile"), 'compiler') + if __name__ == '__main__': SUITE = unittest.TestSuite() TEST_LOADER = unittest.TestLoader() SUITE.addTest(doctest.DocTestSuite(bootstrap)) SUITE.addTests([ TEST_LOADER.loadTestsFromTestCase(VerifyTestCase), + TEST_LOADER.loadTestsFromTestCase(GenerateAndParseConfig), TEST_LOADER.loadTestsFromTestCase(ProgramOutOfDate)]) RUNNER = unittest.TextTestRunner(stream=sys.stdout, verbosity=2) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index bb07ca1908e..83a6d0ad292 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -919,9 +919,9 @@ impl<'a> Builder<'a> { host: TargetSelection, target: TargetSelection, ) -> Compiler { - if self.build.force_use_stage2() { + if self.build.force_use_stage2(stage) { self.compiler(2, self.config.build) - } else if self.build.force_use_stage1(Compiler { stage, host }, target) { + } else if self.build.force_use_stage1(stage, target) { self.compiler(1, self.config.build) } else { self.compiler(stage, host) @@ -1303,6 +1303,14 @@ impl<'a> Builder<'a> { } }; + // By default, windows-rs depends on a native library that doesn't get copied into the + // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native + // library unnecessary. This can be removed when windows-rs enables raw-dylib + // unconditionally. + if let Mode::Rustc | Mode::ToolRustc = mode { + rustflags.arg("--cfg=windows_raw_dylib"); + } + if use_new_symbol_mangling { rustflags.arg("-Csymbol-mangling-version=v0"); } else { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 8b80dfc0f9b..54971af644c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -339,6 +339,12 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car "" }; + // `libtest` uses this to know whether or not to support + // `-Zunstable-options`. + if !builder.unstable_features() { + cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); + } + let mut features = String::new(); // Cranelift doesn't support `asm`. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 58729f396f0..95625170478 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -87,6 +87,9 @@ pub struct Config { pub patch_binaries_for_nix: bool, pub stage0_metadata: Stage0Metadata, + pub stdout_is_tty: bool, + pub stderr_is_tty: bool, + pub on_fail: Option<String>, pub stage: u32, pub keep_stage: Vec<u32>, @@ -191,6 +194,7 @@ pub struct Config { pub dist_sign_folder: Option<PathBuf>, pub dist_upload_addr: Option<String>, pub dist_compression_formats: Option<Vec<String>>, + pub dist_compression_profile: String, pub dist_include_mingw_linker: bool, // libstd features @@ -703,6 +707,7 @@ define_config! { src_tarball: Option<bool> = "src-tarball", missing_tools: Option<bool> = "missing-tools", compression_formats: Option<Vec<String>> = "compression-formats", + compression_profile: Option<String> = "compression-profile", include_mingw_linker: Option<bool> = "include-mingw-linker", } } @@ -821,6 +826,10 @@ impl Config { config.deny_warnings = true; config.bindir = "bin".into(); config.dist_include_mingw_linker = true; + config.dist_compression_profile = "fast".into(); + + config.stdout_is_tty = atty::is(atty::Stream::Stdout); + config.stderr_is_tty = atty::is(atty::Stream::Stderr); // set by build.rs config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); @@ -1153,6 +1162,11 @@ impl Config { config.rust_profile_generate = flags.rust_profile_generate; } + // rust_info must be set before is_ci_llvm_available() is called. + let default = config.channel == "dev"; + config.ignore_git = ignore_git.unwrap_or(default); + config.rust_info = GitInfo::new(config.ignore_git, &config.src); + if let Some(llvm) = toml.llvm { match llvm.ccache { Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), @@ -1303,6 +1317,7 @@ impl Config { config.dist_sign_folder = t.sign_folder.map(PathBuf::from); config.dist_upload_addr = t.upload_addr; config.dist_compression_formats = t.compression_formats; + set(&mut config.dist_compression_profile, t.compression_profile); set(&mut config.rust_dist_src, t.src_tarball); set(&mut config.missing_tools, t.missing_tools); set(&mut config.dist_include_mingw_linker, t.include_mingw_linker) @@ -1346,10 +1361,6 @@ impl Config { config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools); config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(0); - let default = config.channel == "dev"; - config.ignore_git = ignore_git.unwrap_or(default); - config.rust_info = GitInfo::new(config.ignore_git, &config.src); - let download_rustc = config.download_rustc_commit.is_some(); // See https://github.com/rust-lang/compiler-team/issues/326 config.stage = match config.cmd { diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index b326ae402aa..abd28b4005d 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -205,77 +205,78 @@ if '--help' in sys.argv or '-h' in sys.argv: # Parse all command line arguments into one of these three lists, handling # boolean and value-based options separately -unknown_args = [] -need_value_args = [] -known_args = {} - -p("processing command line") -i = 1 -while i < len(sys.argv): - arg = sys.argv[i] - i += 1 - if not arg.startswith('--'): - unknown_args.append(arg) - continue - - found = False - for option in options: - value = None - if option.value: - keyval = arg[2:].split('=', 1) - key = keyval[0] - if option.name != key: - continue +def parse_args(args): + unknown_args = [] + need_value_args = [] + known_args = {} + + i = 0 + while i < len(args): + arg = args[i] + i += 1 + if not arg.startswith('--'): + unknown_args.append(arg) + continue - if len(keyval) > 1: - value = keyval[1] - elif i < len(sys.argv): - value = sys.argv[i] - i += 1 - else: - need_value_args.append(arg) - continue - else: - if arg[2:] == 'enable-' + option.name: - value = True - elif arg[2:] == 'disable-' + option.name: - value = False + found = False + for option in options: + value = None + if option.value: + keyval = arg[2:].split('=', 1) + key = keyval[0] + if option.name != key: + continue + + if len(keyval) > 1: + value = keyval[1] + elif i < len(args): + value = args[i] + i += 1 + else: + need_value_args.append(arg) + continue else: - continue + if arg[2:] == 'enable-' + option.name: + value = True + elif arg[2:] == 'disable-' + option.name: + value = False + else: + continue + + found = True + if option.name not in known_args: + known_args[option.name] = [] + known_args[option.name].append((option, value)) + break + + if not found: + unknown_args.append(arg) + + # Note: here and a few other places, we use [-1] to apply the *last* value + # passed. But if option-checking is enabled, then the known_args loop will + # also assert that options are only passed once. + option_checking = ('option-checking' not in known_args + or known_args['option-checking'][-1][1]) + if option_checking: + if len(unknown_args) > 0: + err("Option '" + unknown_args[0] + "' is not recognized") + if len(need_value_args) > 0: + err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0])) + + config = {} + + set('build.configure-args', sys.argv[1:], config) + apply_args(known_args, option_checking, config) + return parse_example_config(known_args, config) - found = True - if option.name not in known_args: - known_args[option.name] = [] - known_args[option.name].append((option, value)) - break - - if not found: - unknown_args.append(arg) -p("") - -# Note: here and a few other places, we use [-1] to apply the *last* value -# passed. But if option-checking is enabled, then the known_args loop will -# also assert that options are only passed once. -option_checking = ('option-checking' not in known_args - or known_args['option-checking'][-1][1]) -if option_checking: - if len(unknown_args) > 0: - err("Option '" + unknown_args[0] + "' is not recognized") - if len(need_value_args) > 0: - err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0])) - -# Parse all known arguments into a configuration structure that reflects the -# TOML we're going to write out -config = {} - - -def build(): + +def build(known_args): if 'build' in known_args: return known_args['build'][-1][1] return bootstrap.default_build_triple(verbose=False) -def set(key, value): +def set(key, value, config): if isinstance(value, list): # Remove empty values, which value.split(',') tends to generate. value = [v for v in value if v] @@ -297,75 +298,76 @@ def set(key, value): arr = arr[part] -for key in known_args: - # The `set` option is special and can be passed a bunch of times - if key == 'set': - for option, value in known_args[key]: - keyval = value.split('=', 1) - if len(keyval) == 1 or keyval[1] == "true": - value = True - elif keyval[1] == "false": - value = False - else: - value = keyval[1] - set(keyval[0], value) - continue - - # Ensure each option is only passed once - arr = known_args[key] - if option_checking and len(arr) > 1: - err("Option '{}' provided more than once".format(key)) - option, value = arr[-1] - - # If we have a clear avenue to set our value in rustbuild, do so - if option.rustbuild is not None: - set(option.rustbuild, value) - continue - - # Otherwise we're a "special" option and need some extra handling, so do - # that here. - if option.name == 'sccache': - set('llvm.ccache', 'sccache') - elif option.name == 'local-rust': - for path in os.environ['PATH'].split(os.pathsep): - if os.path.exists(path + '/rustc'): - set('build.rustc', path + '/rustc') - break - for path in os.environ['PATH'].split(os.pathsep): - if os.path.exists(path + '/cargo'): - set('build.cargo', path + '/cargo') - break - elif option.name == 'local-rust-root': - set('build.rustc', value + '/bin/rustc') - set('build.cargo', value + '/bin/cargo') - elif option.name == 'llvm-root': - set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config') - elif option.name == 'llvm-config': - set('target.{}.llvm-config'.format(build()), value) - elif option.name == 'llvm-filecheck': - set('target.{}.llvm-filecheck'.format(build()), value) - elif option.name == 'tools': - set('build.tools', value.split(',')) - elif option.name == 'codegen-backends': - set('rust.codegen-backends', value.split(',')) - elif option.name == 'host': - set('build.host', value.split(',')) - elif option.name == 'target': - set('build.target', value.split(',')) - elif option.name == 'full-tools': - set('rust.codegen-backends', ['llvm']) - set('rust.lld', True) - set('rust.llvm-tools', True) - set('build.extended', True) - elif option.name == 'option-checking': - # this was handled above - pass - elif option.name == 'dist-compression-formats': - set('dist.compression-formats', value.split(',')) - else: - raise RuntimeError("unhandled option {}".format(option.name)) +def apply_args(known_args, option_checking, config): + for key in known_args: + # The `set` option is special and can be passed a bunch of times + if key == 'set': + for option, value in known_args[key]: + keyval = value.split('=', 1) + if len(keyval) == 1 or keyval[1] == "true": + value = True + elif keyval[1] == "false": + value = False + else: + value = keyval[1] + set(keyval[0], value, config) + continue -set('build.configure-args', sys.argv[1:]) + # Ensure each option is only passed once + arr = known_args[key] + if option_checking and len(arr) > 1: + err("Option '{}' provided more than once".format(key)) + option, value = arr[-1] + + # If we have a clear avenue to set our value in rustbuild, do so + if option.rustbuild is not None: + set(option.rustbuild, value, config) + continue + + # Otherwise we're a "special" option and need some extra handling, so do + # that here. + build_triple = build(known_args) + + if option.name == 'sccache': + set('llvm.ccache', 'sccache', config) + elif option.name == 'local-rust': + for path in os.environ['PATH'].split(os.pathsep): + if os.path.exists(path + '/rustc'): + set('build.rustc', path + '/rustc', config) + break + for path in os.environ['PATH'].split(os.pathsep): + if os.path.exists(path + '/cargo'): + set('build.cargo', path + '/cargo', config) + break + elif option.name == 'local-rust-root': + set('build.rustc', value + '/bin/rustc', config) + set('build.cargo', value + '/bin/cargo', config) + elif option.name == 'llvm-root': + set('target.{}.llvm-config'.format(build_triple), value + '/bin/llvm-config', config) + elif option.name == 'llvm-config': + set('target.{}.llvm-config'.format(build_triple), value, config) + elif option.name == 'llvm-filecheck': + set('target.{}.llvm-filecheck'.format(build_triple), value, config) + elif option.name == 'tools': + set('build.tools', value.split(','), config) + elif option.name == 'codegen-backends': + set('rust.codegen-backends', value.split(','), config) + elif option.name == 'host': + set('build.host', value.split(','), config) + elif option.name == 'target': + set('build.target', value.split(','), config) + elif option.name == 'full-tools': + set('rust.codegen-backends', ['llvm'], config) + set('rust.lld', True, config) + set('rust.llvm-tools', True, config) + set('build.extended', True, config) + elif option.name == 'option-checking': + # this was handled above + pass + elif option.name == 'dist-compression-formats': + set('dist.compression-formats', value.split(','), config) + else: + raise RuntimeError("unhandled option {}".format(option.name)) # "Parse" the `config.example.toml` file into the various sections, and we'll # use this as a template of a `config.toml` to write out which preserves @@ -373,46 +375,50 @@ set('build.configure-args', sys.argv[1:]) # # Note that the `target` section is handled separately as we'll duplicate it # per configured target, so there's a bit of special handling for that here. -sections = {} -cur_section = None -sections[None] = [] -section_order = [None] -targets = {} -top_level_keys = [] - -for line in open(rust_dir + '/config.example.toml').read().split("\n"): - if cur_section == None: - if line.count('=') == 1: - top_level_key = line.split('=')[0] - top_level_key = top_level_key.strip(' #') - top_level_keys.append(top_level_key) - if line.startswith('['): - cur_section = line[1:-1] - if cur_section.startswith('target'): - cur_section = 'target' - elif '.' in cur_section: - raise RuntimeError("don't know how to deal with section: {}".format(cur_section)) - sections[cur_section] = [line] - section_order.append(cur_section) - else: - sections[cur_section].append(line) - -# Fill out the `targets` array by giving all configured targets a copy of the -# `target` section we just loaded from the example config -configured_targets = [build()] -if 'build' in config: - if 'host' in config['build']: - configured_targets += config['build']['host'] - if 'target' in config['build']: - configured_targets += config['build']['target'] -if 'target' in config: - for target in config['target']: - configured_targets.append(target) -for target in configured_targets: - targets[target] = sections['target'][:] - # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target. - # Avoid using quotes unless it's necessary. - targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target) +def parse_example_config(known_args, config): + sections = {} + cur_section = None + sections[None] = [] + section_order = [None] + targets = {} + top_level_keys = [] + + for line in open(rust_dir + '/config.example.toml').read().split("\n"): + if cur_section == None: + if line.count('=') == 1: + top_level_key = line.split('=')[0] + top_level_key = top_level_key.strip(' #') + top_level_keys.append(top_level_key) + if line.startswith('['): + cur_section = line[1:-1] + if cur_section.startswith('target'): + cur_section = 'target' + elif '.' in cur_section: + raise RuntimeError("don't know how to deal with section: {}".format(cur_section)) + sections[cur_section] = [line] + section_order.append(cur_section) + else: + sections[cur_section].append(line) + + # Fill out the `targets` array by giving all configured targets a copy of the + # `target` section we just loaded from the example config + configured_targets = [build(known_args)] + if 'build' in config: + if 'host' in config['build']: + configured_targets += config['build']['host'] + if 'target' in config['build']: + configured_targets += config['build']['target'] + if 'target' in config: + for target in config['target']: + configured_targets.append(target) + for target in configured_targets: + targets[target] = sections['target'][:] + # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target. + # Avoid using quotes unless it's necessary. + targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target) + + configure_file(sections, top_level_keys, targets, config) + return section_order, sections, targets def is_number(value): @@ -475,17 +481,20 @@ def configure_top_level_key(lines, top_level_key, value): raise RuntimeError("failed to find config line for {}".format(top_level_key)) -for section_key, section_config in config.items(): - if section_key not in sections and section_key not in top_level_keys: - raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key)) - if section_key in top_level_keys: - configure_top_level_key(sections[None], section_key, section_config) +# Modify `sections` to reflect the parsed arguments and example configs. +def configure_file(sections, top_level_keys, targets, config): + for section_key, section_config in config.items(): + if section_key not in sections and section_key not in top_level_keys: + raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key)) + if section_key in top_level_keys: + configure_top_level_key(sections[None], section_key, section_config) + + elif section_key == 'target': + for target in section_config: + configure_section(targets[target], section_config[target]) + else: + configure_section(sections[section_key], section_config) - elif section_key == 'target': - for target in section_config: - configure_section(targets[target], section_config[target]) - else: - configure_section(sections[section_key], section_config) def write_uncommented(target, f): block = [] @@ -503,24 +512,36 @@ def write_uncommented(target, f): is_comment = is_comment and line.startswith('#') return f -# Now that we've built up our `config.toml`, write it all out in the same -# order that we read it in. -p("") -p("writing `config.toml` in current directory") -with bootstrap.output('config.toml') as f: + +def write_config_toml(writer, section_order, targets, sections): for section in section_order: if section == 'target': for target in targets: - f = write_uncommented(targets[target], f) + writer = write_uncommented(targets[target], writer) else: - f = write_uncommented(sections[section], f) - -with bootstrap.output('Makefile') as f: - contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in') - contents = open(contents).read() - contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/') - contents = contents.replace("$(CFG_PYTHON)", sys.executable) - f.write(contents) - -p("") -p("run `python {}/x.py --help`".format(rust_dir)) + writer = write_uncommented(sections[section], writer) + + +if __name__ == "__main__": + p("processing command line") + # Parse all known arguments into a configuration structure that reflects the + # TOML we're going to write out + p("") + section_order, sections, targets = parse_args(sys.argv[1:]) + + # Now that we've built up our `config.toml`, write it all out in the same + # order that we read it in. + p("") + p("writing `config.toml` in current directory") + with bootstrap.output('config.toml') as f: + write_config_toml(f, section_order, targets, sections) + + with bootstrap.output('Makefile') as f: + contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in') + contents = open(contents).read() + contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/') + contents = contents.replace("$(CFG_PYTHON)", sys.executable) + f.write(contents) + + p("") + p("run `python {}/x.py --help`".format(rust_dir)) diff --git a/src/bootstrap/defaults/config.user.toml b/src/bootstrap/defaults/config.user.toml index 48ae2fe448d..ee271c3fb51 100644 --- a/src/bootstrap/defaults/config.user.toml +++ b/src/bootstrap/defaults/config.user.toml @@ -11,3 +11,7 @@ extended = true [llvm] # Most users installing from source want to build all parts of the project from source, not just rustc itself. download-ci-llvm = false + +[dist] +# Use better compression when preparing tarballs. +compression-profile = "balanced" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index a3d9cb3e10c..dceb4bd1b89 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -210,6 +210,8 @@ fn make_win_dist( rustc_dlls.push("libgcc_s_seh-1.dll"); } + // Libraries necessary to link the windows-gnu toolchains. + // System libraries will be preferred if they are available (see #67429). let target_libs = [ //MinGW libs "libgcc.a", @@ -223,6 +225,7 @@ fn make_win_dist( "libmoldname.a", "libpthread.a", //Windows import libs + //This should contain only the set of libraries necessary to link the standard library. "libadvapi32.a", "libbcrypt.a", "libcomctl32.a", @@ -236,6 +239,7 @@ fn make_win_dist( "libkernel32.a", "libmsimg32.a", "libmsvcrt.a", + "libntdll.a", "libodbc32.a", "libole32.a", "liboleaut32.a", diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 94630e40f3c..36f9aaa595d 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/104748 +Last change is for: https://github.com/rust-lang/rust/pull/109373 diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index ac3843c3344..42d895a3413 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -210,10 +210,13 @@ install!((self, builder, _config), } }; LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, { - let tarball = builder - .ensure(dist::LlvmTools { target: self.target }) - .expect("missing llvm-tools"); - install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); + if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) { + install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); + } else { + builder.info( + &format!("skipping llvm-tools stage{} ({}): external LLVM", self.compiler.stage, self.target), + ); + } }; Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::Rustfmt { diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index 5c0322e18a4..4fb00f65dc1 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -27,52 +27,54 @@ //! Note that this module has a #[cfg(windows)] above it as none of this logic //! is required on Unix. -#![allow(nonstandard_style, dead_code)] - use crate::Build; use std::env; +use std::ffi::c_void; use std::io; use std::mem; -use std::ptr; -use winapi::shared::minwindef::{DWORD, FALSE, LPVOID}; -use winapi::um::errhandlingapi::SetErrorMode; -use winapi::um::handleapi::{CloseHandle, DuplicateHandle}; -use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject}; -use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess}; -use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX}; -use winapi::um::winnt::{ - JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, - JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE, +use windows::{ + core::PCWSTR, + Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE}, + Win32::System::Diagnostics::Debug::{SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE}, + Win32::System::JobObjects::{ + AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation, + SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, + }, + Win32::System::Threading::{ + GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE, + }, }; pub unsafe fn setup(build: &mut Build) { // Enable the Windows Error Reporting dialog which msys disables, // so we can JIT debug rustc - let mode = SetErrorMode(0); + let mode = SetErrorMode(THREAD_ERROR_MODE::default()); + let mode = THREAD_ERROR_MODE(mode); SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); // Create a new job object for us to use - let job = CreateJobObjectW(ptr::null_mut(), ptr::null()); - assert!(!job.is_null(), "{}", io::Error::last_os_error()); + let job = CreateJobObjectW(None, PCWSTR::null()).unwrap(); // Indicate that when all handles to the job object are gone that all // process in the object should be killed. Note that this includes our // entire process tree by default because we've added ourselves and our // children will reside in the job by default. - let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>(); + let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default(); info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if build.config.low_priority { info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS; - info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS; + info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0; } let r = SetInformationJobObject( job, JobObjectExtendedLimitInformation, - &mut info as *mut _ as LPVOID, - mem::size_of_val(&info) as DWORD, - ); - assert!(r != 0, "{}", io::Error::last_os_error()); + &info as *const _ as *const c_void, + mem::size_of_val(&info) as u32, + ) + .ok(); + assert!(r.is_ok(), "{}", io::Error::last_os_error()); // Assign our process to this job object. Note that if this fails, one very // likely reason is that we are ourselves already in a job object! This can @@ -83,8 +85,8 @@ pub unsafe fn setup(build: &mut Build) { // Also note that nested jobs (why this might fail) are supported in recent // versions of Windows, but the version of Windows that our bots are running // at least don't support nested job objects. - let r = AssignProcessToJobObject(job, GetCurrentProcess()); - if r == 0 { + let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok(); + if r.is_err() { CloseHandle(job); return; } @@ -102,31 +104,32 @@ pub unsafe fn setup(build: &mut Build) { Err(..) => return, }; - let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap()); - - // If we get a null parent pointer here, it is possible that either - // we have got an invalid pid or the parent process has been closed. - // Since the first case rarely happens - // (only when wrongly setting the environmental variable), - // so it might be better to improve the experience of the second case - // when users have interrupted the parent process and we don't finish - // duplicating the handle yet. - // We just need close the job object if that occurs. - if parent.is_null() { - CloseHandle(job); - return; - } + let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() { + Some(parent) => parent, + _ => { + // If we get a null parent pointer here, it is possible that either + // we have an invalid pid or the parent process has been closed. + // Since the first case rarely happens + // (only when wrongly setting the environmental variable), + // it might be better to improve the experience of the second case + // when users have interrupted the parent process and we haven't finish + // duplicating the handle yet. We just need close the job object if that occurs. + CloseHandle(job); + return; + } + }; - let mut parent_handle = ptr::null_mut(); + let mut parent_handle = HANDLE::default(); let r = DuplicateHandle( GetCurrentProcess(), job, parent, &mut parent_handle, 0, - FALSE, + false, DUPLICATE_SAME_ACCESS, - ); + ) + .ok(); // If this failed, well at least we tried! An example of DuplicateHandle // failing in the past has been when the wrong python2 package spawned this @@ -134,7 +137,7 @@ pub unsafe fn setup(build: &mut Build) { // `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure // mode" here is that we only clean everything up when the build system // dies, not when the python parent does, so not too bad. - if r != 0 { + if r.is_err() { CloseHandle(job); } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f136690592d..54aa5a585bb 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -55,6 +55,7 @@ mod format; mod install; mod metadata; mod native; +mod render_tests; mod run; mod sanity; mod setup; @@ -88,6 +89,7 @@ pub use crate::builder::PathSet; use crate::cache::{Interned, INTERNER}; pub use crate::config::Config; pub use crate::flags::Subcommand; +use termcolor::{ColorChoice, StandardStream, WriteColor}; const LLVM_TOOLS: &[&str] = &[ "llvm-cov", // used to generate coverage report @@ -144,6 +146,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] // FIXME: Used by filetime, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "emulate_second_only_system", None), (Some(Mode::ToolRustc), "emulate_second_only_system", None), + // Needed to avoid the need to copy windows.lib into the sysroot. + (Some(Mode::Rustc), "windows_raw_dylib", None), + (Some(Mode::ToolRustc), "windows_raw_dylib", None), ]; /// A structure representing a Rust compiler. @@ -1199,19 +1204,20 @@ impl Build { /// /// When all of these conditions are met the build will lift artifacts from /// the previous stage forward. - fn force_use_stage1(&self, compiler: Compiler, target: TargetSelection) -> bool { + fn force_use_stage1(&self, stage: u32, target: TargetSelection) -> bool { !self.config.full_bootstrap - && compiler.stage >= 2 + && !self.config.download_rustc() + && stage >= 2 && (self.hosts.iter().any(|h| *h == target) || target == self.build) } /// Checks whether the `compiler` compiling for `target` should be forced to /// use a stage2 compiler instead. /// - /// When we download the pre-compiled version of rustc it should be forced to - /// use a stage2 compiler. - fn force_use_stage2(&self) -> bool { - self.config.download_rustc() + /// When we download the pre-compiled version of rustc and compiler stage is >= 2, + /// it should be forced to use a stage2 compiler. + fn force_use_stage2(&self, stage: u32) -> bool { + self.config.download_rustc() && stage >= 2 } /// Given `num` in the form "a.b.c" return a "release string" which @@ -1579,6 +1585,31 @@ to download LLVM rather than building it. self.config.ninja_in_file } + + pub fn colored_stdout<R, F: FnOnce(&mut dyn WriteColor) -> R>(&self, f: F) -> R { + self.colored_stream_inner(StandardStream::stdout, self.config.stdout_is_tty, f) + } + + pub fn colored_stderr<R, F: FnOnce(&mut dyn WriteColor) -> R>(&self, f: F) -> R { + self.colored_stream_inner(StandardStream::stderr, self.config.stderr_is_tty, f) + } + + fn colored_stream_inner<R, F, C>(&self, constructor: C, is_tty: bool, f: F) -> R + where + C: Fn(ColorChoice) -> StandardStream, + F: FnOnce(&mut dyn WriteColor) -> R, + { + let choice = match self.config.color { + flags::Color::Always => ColorChoice::Always, + flags::Color::Never => ColorChoice::Never, + flags::Color::Auto if !is_tty => ColorChoice::Never, + flags::Color::Auto => ColorChoice::Auto, + }; + let mut stream = constructor(choice); + let result = f(&mut stream); + stream.reset().unwrap(); + result + } } #[cfg(unix)] diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index 2e62c950709..5f254761aa1 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -51,6 +51,7 @@ impl BuildMetrics { duration_excluding_children_sec: Duration::ZERO, children: Vec::new(), + tests: Vec::new(), }); } @@ -72,6 +73,16 @@ impl BuildMetrics { } } + pub(crate) fn record_test(&self, name: &str, outcome: TestOutcome) { + let mut state = self.state.borrow_mut(); + state + .running_steps + .last_mut() + .unwrap() + .tests + .push(Test { name: name.to_string(), outcome }); + } + fn collect_stats(&self, state: &mut MetricsState) { let step = state.running_steps.last_mut().unwrap(); @@ -125,6 +136,14 @@ impl BuildMetrics { } fn prepare_json_step(&self, step: StepMetrics) -> JsonNode { + let mut children = Vec::new(); + children.extend(step.children.into_iter().map(|child| self.prepare_json_step(child))); + children.extend( + step.tests + .into_iter() + .map(|test| JsonNode::Test { name: test.name, outcome: test.outcome }), + ); + JsonNode::RustbuildStep { type_: step.type_, debug_repr: step.debug_repr, @@ -135,11 +154,7 @@ impl BuildMetrics { / step.duration_excluding_children_sec.as_secs_f64(), }, - children: step - .children - .into_iter() - .map(|child| self.prepare_json_step(child)) - .collect(), + children, } } } @@ -161,6 +176,12 @@ struct StepMetrics { duration_excluding_children_sec: Duration, children: Vec<StepMetrics>, + tests: Vec<Test>, +} + +struct Test { + name: String, + outcome: TestOutcome, } #[derive(Serialize, Deserialize)] @@ -190,6 +211,19 @@ enum JsonNode { children: Vec<JsonNode>, }, + Test { + name: String, + #[serde(flatten)] + outcome: TestOutcome, + }, +} + +#[derive(Serialize, Deserialize)] +#[serde(tag = "outcome", rename_all = "snake_case")] +pub(crate) enum TestOutcome { + Passed, + Failed, + Ignored { ignore_reason: Option<String> }, } #[derive(Serialize, Deserialize)] diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 41ee5096553..f27db5c91e2 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -309,6 +309,7 @@ impl Step for Llvm { cfg.out_dir(&out_dir) .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) + .define("LLVM_UNREACHABLE_OPTIMIZE", "OFF") .define("LLVM_ENABLE_PLUGINS", plugins) .define("LLVM_TARGETS_TO_BUILD", llvm_targets) .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets) @@ -567,6 +568,8 @@ fn configure_cmake( cfg.define("CMAKE_SYSTEM_NAME", "Haiku"); } else if target.contains("solaris") || target.contains("illumos") { cfg.define("CMAKE_SYSTEM_NAME", "SunOS"); + } else if target.contains("linux") { + cfg.define("CMAKE_SYSTEM_NAME", "Linux"); } // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in // that case like CMake we cannot easily determine system version either. diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs new file mode 100644 index 00000000000..af2370d439e --- /dev/null +++ b/src/bootstrap/render_tests.rs @@ -0,0 +1,376 @@ +//! This module renders the JSON output of libtest into a human-readable form, trying to be as +//! similar to libtest's native output as possible. +//! +//! This is needed because we need to use libtest in JSON mode to extract granluar information +//! about the executed tests. Doing so suppresses the human-readable output, and (compared to Cargo +//! and rustc) libtest doesn't include the rendered human-readable output as a JSON field. We had +//! to reimplement all the rendering logic in this module because of that. + +use crate::builder::Builder; +use std::io::{BufRead, BufReader, Write}; +use std::process::{ChildStdout, Command, Stdio}; +use std::time::Duration; +use termcolor::{Color, ColorSpec, WriteColor}; + +const TERSE_TESTS_PER_LINE: usize = 88; + +pub(crate) fn add_flags_and_try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { + if cmd.get_args().position(|arg| arg == "--").is_none() { + cmd.arg("--"); + } + cmd.args(&["-Z", "unstable-options", "--format", "json"]); + + try_run_tests(builder, cmd) +} + +pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { + if builder.config.dry_run() { + return true; + } + + if !run_tests(builder, cmd) { + if builder.fail_fast { + crate::detail_exit(1); + } else { + let mut failures = builder.delayed_failures.borrow_mut(); + failures.push(format!("{cmd:?}")); + false + } + } else { + true + } +} + +fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { + cmd.stdout(Stdio::piped()); + + builder.verbose(&format!("running: {cmd:?}")); + + let mut process = cmd.spawn().unwrap(); + + // This runs until the stdout of the child is closed, which means the child exited. We don't + // run this on another thread since the builder is not Sync. + Renderer::new(process.stdout.take().unwrap(), builder).render_all(); + + let result = process.wait_with_output().unwrap(); + if !result.status.success() && builder.is_verbose() { + println!( + "\n\ncommand did not execute successfully: {cmd:?}\n\ + expected success, got: {}", + result.status + ); + } + + result.status.success() +} + +struct Renderer<'a> { + stdout: BufReader<ChildStdout>, + failures: Vec<TestOutcome>, + benches: Vec<BenchOutcome>, + builder: &'a Builder<'a>, + tests_count: Option<usize>, + executed_tests: usize, + terse_tests_in_line: usize, +} + +impl<'a> Renderer<'a> { + fn new(stdout: ChildStdout, builder: &'a Builder<'a>) -> Self { + Self { + stdout: BufReader::new(stdout), + benches: Vec::new(), + failures: Vec::new(), + builder, + tests_count: None, + executed_tests: 0, + terse_tests_in_line: 0, + } + } + + fn render_all(mut self) { + let mut line = String::new(); + loop { + line.clear(); + match self.stdout.read_line(&mut line) { + Ok(_) => {} + Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => break, + Err(err) => panic!("failed to read output of test runner: {err}"), + } + if line.is_empty() { + break; + } + + let trimmed = line.trim(); + if trimmed.starts_with("{") && trimmed.ends_with("}") { + self.render_message(match serde_json::from_str(&trimmed) { + Ok(parsed) => parsed, + Err(err) => { + panic!("failed to parse libtest json output; error: {err}, line: {line:?}"); + } + }); + } else { + // Handle non-JSON output, for example when --nocapture is passed. + print!("{line}"); + let _ = std::io::stdout().flush(); + } + } + } + + fn render_test_outcome(&mut self, outcome: Outcome<'_>, test: &TestOutcome) { + self.executed_tests += 1; + + #[cfg(feature = "build-metrics")] + self.builder.metrics.record_test( + &test.name, + match outcome { + Outcome::Ok | Outcome::BenchOk => crate::metrics::TestOutcome::Passed, + Outcome::Failed => crate::metrics::TestOutcome::Failed, + Outcome::Ignored { reason } => crate::metrics::TestOutcome::Ignored { + ignore_reason: reason.map(|s| s.to_string()), + }, + }, + ); + + if self.builder.config.verbose_tests { + self.render_test_outcome_verbose(outcome, test); + } else { + self.render_test_outcome_terse(outcome, test); + } + } + + fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) { + print!("test {} ... ", test.name); + self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); + if let Some(exec_time) = test.exec_time { + print!(" ({exec_time:.2?})"); + } + println!(); + } + + fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, _: &TestOutcome) { + if self.terse_tests_in_line != 0 && self.terse_tests_in_line % TERSE_TESTS_PER_LINE == 0 { + if let Some(total) = self.tests_count { + let total = total.to_string(); + let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len()); + print!(" {executed}/{total}"); + } + println!(); + self.terse_tests_in_line = 0; + } + + self.terse_tests_in_line += 1; + self.builder.colored_stdout(|stdout| outcome.write_short(stdout)).unwrap(); + let _ = std::io::stdout().flush(); + } + + fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) { + // The terse output doesn't end with a newline, so we need to add it ourselves. + if !self.builder.config.verbose_tests { + println!(); + } + + if !self.failures.is_empty() { + println!("\nfailures:\n"); + for failure in &self.failures { + if let Some(stdout) = &failure.stdout { + println!("---- {} stdout ----", failure.name); + println!("{stdout}"); + } + } + + println!("\nfailures:"); + for failure in &self.failures { + println!(" {}", failure.name); + } + } + + if !self.benches.is_empty() { + println!("\nbenchmarks:"); + + let mut rows = Vec::new(); + for bench in &self.benches { + rows.push(( + &bench.name, + format!("{:.2?}/iter", Duration::from_nanos(bench.median)), + format!("+/- {:.2?}", Duration::from_nanos(bench.deviation)), + )); + } + + let max_0 = rows.iter().map(|r| r.0.len()).max().unwrap_or(0); + let max_1 = rows.iter().map(|r| r.1.len()).max().unwrap_or(0); + let max_2 = rows.iter().map(|r| r.2.len()).max().unwrap_or(0); + for row in &rows { + println!(" {:<max_0$} {:>max_1$} {:>max_2$}", row.0, row.1, row.2); + } + } + + print!("\ntest result: "); + self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); + println!( + ". {} passed; {} failed; {} ignored; {} measured; {} filtered out; \ + finished in {:.2?}\n", + suite.passed, + suite.failed, + suite.ignored, + suite.measured, + suite.filtered_out, + Duration::from_secs_f64(suite.exec_time) + ); + } + + fn render_message(&mut self, message: Message) { + match message { + Message::Suite(SuiteMessage::Started { test_count }) => { + println!("\nrunning {test_count} tests"); + self.executed_tests = 0; + self.terse_tests_in_line = 0; + self.tests_count = Some(test_count); + } + Message::Suite(SuiteMessage::Ok(outcome)) => { + self.render_suite_outcome(Outcome::Ok, &outcome); + } + Message::Suite(SuiteMessage::Failed(outcome)) => { + self.render_suite_outcome(Outcome::Failed, &outcome); + } + Message::Bench(outcome) => { + // The formatting for benchmarks doesn't replicate 1:1 the formatting libtest + // outputs, mostly because libtest's formatting is broken in terse mode, which is + // the default used by our monorepo. We use a different formatting instead: + // successful benchmarks are just showed as "benchmarked"/"b", and the details are + // outputted at the bottom like failures. + let fake_test_outcome = TestOutcome { + name: outcome.name.clone(), + exec_time: None, + stdout: None, + message: None, + }; + self.render_test_outcome(Outcome::BenchOk, &fake_test_outcome); + self.benches.push(outcome); + } + Message::Test(TestMessage::Ok(outcome)) => { + self.render_test_outcome(Outcome::Ok, &outcome); + } + Message::Test(TestMessage::Ignored(outcome)) => { + self.render_test_outcome( + Outcome::Ignored { reason: outcome.message.as_deref() }, + &outcome, + ); + } + Message::Test(TestMessage::Failed(outcome)) => { + self.render_test_outcome(Outcome::Failed, &outcome); + self.failures.push(outcome); + } + Message::Test(TestMessage::Timeout { name }) => { + println!("test {name} has been running for a long time"); + } + Message::Test(TestMessage::Started) => {} // Not useful + } + } +} + +enum Outcome<'a> { + Ok, + BenchOk, + Failed, + Ignored { reason: Option<&'a str> }, +} + +impl Outcome<'_> { + fn write_short(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> { + match self { + Outcome::Ok => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Green)))?; + write!(writer, ".")?; + } + Outcome::BenchOk => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(writer, "b")?; + } + Outcome::Failed => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Red)))?; + write!(writer, "F")?; + } + Outcome::Ignored { .. } => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(writer, "i")?; + } + } + writer.reset() + } + + fn write_long(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> { + match self { + Outcome::Ok => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Green)))?; + write!(writer, "ok")?; + } + Outcome::BenchOk => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(writer, "benchmarked")?; + } + Outcome::Failed => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Red)))?; + write!(writer, "FAILED")?; + } + Outcome::Ignored { reason } => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(writer, "ignored")?; + if let Some(reason) = reason { + write!(writer, ", {reason}")?; + } + } + } + writer.reset() + } +} + +#[derive(serde_derive::Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +enum Message { + Suite(SuiteMessage), + Test(TestMessage), + Bench(BenchOutcome), +} + +#[derive(serde_derive::Deserialize)] +#[serde(tag = "event", rename_all = "snake_case")] +enum SuiteMessage { + Ok(SuiteOutcome), + Failed(SuiteOutcome), + Started { test_count: usize }, +} + +#[derive(serde_derive::Deserialize)] +struct SuiteOutcome { + passed: usize, + failed: usize, + ignored: usize, + measured: usize, + filtered_out: usize, + exec_time: f64, +} + +#[derive(serde_derive::Deserialize)] +#[serde(tag = "event", rename_all = "snake_case")] +enum TestMessage { + Ok(TestOutcome), + Failed(TestOutcome), + Ignored(TestOutcome), + Timeout { name: String }, + Started, +} + +#[derive(serde_derive::Deserialize)] +struct BenchOutcome { + name: String, + median: u64, + deviation: u64, +} + +#[derive(serde_derive::Deserialize)] +struct TestOutcome { + name: String, + exec_time: Option<f64>, + stdout: Option<String>, + message: Option<String>, +} diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index fc850a22b2f..7fa8a4d9d7f 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -318,6 +318,7 @@ impl<'a> Tarball<'a> { assert!(!formats.is_empty(), "dist.compression-formats can't be empty"); cmd.arg("--compression-formats").arg(formats.join(",")); } + cmd.args(&["--compression-profile", &self.builder.config.dist_compression_profile]); self.builder.run(&mut cmd); // Ensure there are no symbolic links in the tarball. In particular, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f5d680df113..29d37c09d88 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -20,6 +20,7 @@ use crate::dist; use crate::doc::DocumentationFormat; use crate::flags::Subcommand; use crate::native; +use crate::render_tests::add_flags_and_try_run_tests; use crate::tool::{self, SourceType, Tool}; use crate::toolstate::ToolState; use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t}; @@ -123,7 +124,7 @@ impl Step for CrateJsonDocLint { SourceType::InTree, &[], ); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -172,7 +173,7 @@ You can skip linkcheck with --exclude src/tools/linkchecker" SourceType::InTree, &[], ); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); // Build all the default documentation. builder.default_doc(&[]); @@ -333,7 +334,7 @@ impl Step for Cargo { cargo.env("PATH", &path_for_cargo(builder, compiler)); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -392,7 +393,7 @@ impl Step for RustAnalyzer { cargo.add_rustc_lib_path(builder, compiler); cargo.arg("--").args(builder.config.cmd.test_args()); - builder.run(&mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -445,7 +446,7 @@ impl Step for Rustfmt { cargo.add_rustc_lib_path(builder, compiler); - builder.run(&mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -496,7 +497,7 @@ impl Step for RustDemangler { cargo.add_rustc_lib_path(builder, compiler); - builder.run(&mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -637,8 +638,7 @@ impl Step for Miri { // Forward test filters. cargo.arg("--").args(builder.config.cmd.test_args()); - let mut cargo = Command::from(cargo); - builder.run(&mut cargo); + add_flags_and_try_run_tests(builder, &mut cargo.into()); // # Run `cargo miri test`. // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures @@ -711,7 +711,7 @@ impl Step for CompiletestTest { ); cargo.allow_features("test"); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -1118,7 +1118,11 @@ impl Step for Tidy { cmd.arg(&builder.src); cmd.arg(&builder.initial_cargo); cmd.arg(&builder.out); - cmd.arg(builder.jobs().to_string()); + // Tidy is heavily IO constrained. Still respect `-j`, but use a higher limit if `jobs` hasn't been configured. + let jobs = builder.config.jobs.unwrap_or_else(|| { + 8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32 + }); + cmd.arg(jobs.to_string()); if builder.is_verbose() { cmd.arg("--verbose"); } @@ -1189,7 +1193,7 @@ impl Step for TidySelfTest { SourceType::InTree, &[], ); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -1616,9 +1620,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--verbose"); } - if !builder.config.verbose_tests { - cmd.arg("--quiet"); - } + cmd.arg("--json"); let mut llvm_components_passed = false; let mut copts_passed = false; @@ -1769,7 +1771,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the suite, mode, &compiler.host, target )); let _time = util::timeit(&builder); - try_run(builder, &mut cmd); + crate::render_tests::try_run_tests(builder, &mut cmd); if let Some(compare_mode) = compare_mode { cmd.arg("--compare-mode").arg(compare_mode); @@ -1778,7 +1780,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the suite, mode, compare_mode, &compiler.host, target )); let _time = util::timeit(&builder); - try_run(builder, &mut cmd); + crate::render_tests::try_run_tests(builder, &mut cmd); } } } @@ -2180,9 +2182,8 @@ impl Step for Crate { cargo.arg("--"); cargo.args(&builder.config.cmd.test_args()); - if !builder.config.verbose_tests { - cargo.arg("--quiet"); - } + cargo.arg("-Z").arg("unstable-options"); + cargo.arg("--format").arg("json"); if target.contains("emscripten") { cargo.env( @@ -2210,7 +2211,7 @@ impl Step for Crate { target )); let _time = util::timeit(&builder); - try_run(builder, &mut cargo.into()); + crate::render_tests::try_run_tests(builder, &mut cargo.into()); } } @@ -2330,7 +2331,7 @@ impl Step for CrateRustdoc { )); let _time = util::timeit(&builder); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -2391,17 +2392,13 @@ impl Step for CrateRustdocJsonTypes { cargo.arg("'-Ctarget-feature=-crt-static'"); } - if !builder.config.verbose_tests { - cargo.arg("--quiet"); - } - builder.info(&format!( "{} rustdoc-json-types stage{} ({} -> {})", test_kind, compiler.stage, &compiler.host, target )); let _time = util::timeit(&builder); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -2570,7 +2567,7 @@ impl Step for Bootstrap { // rustbuild tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. cmd.arg("--test-threads=1"); - try_run(builder, &mut cmd); + add_flags_and_try_run_tests(builder, &mut cmd); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -2651,7 +2648,7 @@ impl Step for ReplacePlaceholderTest { SourceType::InTree, &[], ); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 93e53d383cd..9a6aaffe22b 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -155,29 +155,30 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> { use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; - use std::ptr; - - use winapi::shared::minwindef::{DWORD, WORD}; - use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING}; - use winapi::um::handleapi::CloseHandle; - use winapi::um::ioapiset::DeviceIoControl; - use winapi::um::winbase::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT}; - use winapi::um::winioctl::FSCTL_SET_REPARSE_POINT; - use winapi::um::winnt::{ - FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_WRITE, - IO_REPARSE_TAG_MOUNT_POINT, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, WCHAR, + + use windows::{ + core::PCWSTR, + Win32::Foundation::{CloseHandle, HANDLE}, + Win32::Storage::FileSystem::{ + CreateFileW, FILE_ACCESS_FLAGS, FILE_FLAG_BACKUP_SEMANTICS, + FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, OPEN_EXISTING, + }, + Win32::System::Ioctl::FSCTL_SET_REPARSE_POINT, + Win32::System::SystemServices::{GENERIC_WRITE, IO_REPARSE_TAG_MOUNT_POINT}, + Win32::System::IO::DeviceIoControl, }; #[allow(non_snake_case)] #[repr(C)] struct REPARSE_MOUNTPOINT_DATA_BUFFER { - ReparseTag: DWORD, - ReparseDataLength: DWORD, - Reserved: WORD, - ReparseTargetLength: WORD, - ReparseTargetMaximumLength: WORD, - Reserved1: WORD, - ReparseTarget: WCHAR, + ReparseTag: u32, + ReparseDataLength: u32, + Reserved: u16, + ReparseTargetLength: u16, + ReparseTargetMaximumLength: u16, + Reserved1: u16, + ReparseTarget: u16, } fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> { @@ -193,17 +194,20 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { let path = to_u16s(junction)?; - unsafe { - let h = CreateFileW( - path.as_ptr(), - GENERIC_WRITE, + let h = unsafe { + CreateFileW( + PCWSTR(path.as_ptr()), + FILE_ACCESS_FLAGS(GENERIC_WRITE), FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - ptr::null_mut(), + None, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, - ptr::null_mut(), - ); + HANDLE::default(), + ) + } + .map_err(|_| io::Error::last_os_error())?; + unsafe { #[repr(C, align(8))] struct Align8<T>(T); let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]); @@ -219,27 +223,29 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { } *buf.offset(i) = 0; i += 1; + (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; - (*db).ReparseTargetMaximumLength = (i * 2) as WORD; - (*db).ReparseTargetLength = ((i - 1) * 2) as WORD; - (*db).ReparseDataLength = (*db).ReparseTargetLength as DWORD + 12; + (*db).ReparseTargetMaximumLength = (i * 2) as u16; + (*db).ReparseTargetLength = ((i - 1) * 2) as u16; + (*db).ReparseDataLength = ((*db).ReparseTargetLength + 12) as u32; - let mut ret = 0; - let res = DeviceIoControl( - h as *mut _, + let mut ret = 0u32; + DeviceIoControl( + h, FSCTL_SET_REPARSE_POINT, - db.cast(), + Some(db.cast()), (*db).ReparseDataLength + 8, - ptr::null_mut(), + None, 0, - &mut ret, - ptr::null_mut(), - ); - - let out = if res == 0 { Err(io::Error::last_os_error()) } else { Ok(()) }; - CloseHandle(h); - out + Some(&mut ret), + None, + ) + .ok() + .map_err(|_| io::Error::last_os_error())?; } + + unsafe { CloseHandle(h) }; + Ok(()) } } diff --git a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile index 4e46bdee5ac..2089bf38716 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile @@ -9,10 +9,10 @@ RUN bash /tmp/cross-apt-packages.sh # Required for cross-build gcc RUN apt-get update && \ apt-get install -y --no-install-recommends \ - libgmp-dev \ - libmpfr-dev \ - libmpc-dev \ - && rm -rf /var/lib/apt/lists/* + libgmp-dev \ + libmpfr-dev \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* COPY scripts/illumos-toolchain.sh /tmp/ @@ -28,6 +28,7 @@ RUN /scripts/cmake.sh ENV \ AR_x86_64_unknown_illumos=x86_64-illumos-ar \ + RANLIB_x86_64_unknown_illumos=x86_64-illumos-ranlib \ CC_x86_64_unknown_illumos=x86_64-illumos-gcc \ CXX_x86_64_unknown_illumos=x86_64-illumos-g++ 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 5feba4e0605..04fdb15f5ac 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 @@ -54,8 +54,8 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh ENV CC=clang CXX=clang++ -# rustc-perf version from 2022-07-22 -ENV PERF_COMMIT 3c253134664fdcba862c539d37f0de18557a9a4c +# rustc-perf version from 2023-03-15 +ENV PERF_COMMIT 9dfaa35193154b690922347ee1141a06ec87a199 RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \ unzip perf.zip && \ mv rustc-perf-$PERF_COMMIT rustc-perf && \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh index 9abfd4e9731..de0fb95efd0 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh @@ -4,7 +4,7 @@ set -ex source shared.sh -LLVM=llvmorg-15.0.0 +LLVM=llvmorg-16.0.0-rc4 mkdir llvm-project cd llvm-project diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index d9e58386256..b5abf6564a6 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ lib32z1-dev \ xz-utils \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index 889a586b351..b5715024a84 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile @@ -1,6 +1,8 @@ FROM ubuntu:22.04 ARG DEBIAN_FRONTEND=noninteractive +# NOTE: intentionally uses python2 for x.py so we can test it still works. +# validate-toolstate only runs in our CI, so it's ok for it to only support python3. RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ @@ -8,6 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ file \ curl \ ca-certificates \ + python2.7 \ python3 \ python3-pip \ python3-pkg-resources \ @@ -30,4 +33,4 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ -ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest +ENV SCRIPT python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile index b99a0886b4d..21dcf29b4a9 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile @@ -22,6 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ xz-utils \ nodejs \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile index a007bf183ee..cfb638e8b07 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile @@ -2,7 +2,6 @@ FROM ubuntu:22.04 ARG DEBIAN_FRONTEND=noninteractive -# NOTE: intentionally installs both python2 and python3 so we can test support for both. RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ gcc-multilib \ @@ -11,8 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ file \ curl \ ca-certificates \ - python2.7 \ - python3 \ + python3.11 \ git \ cmake \ sudo \ @@ -25,6 +23,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ xz-utils \ nodejs \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* # Install powershell (universal package) so we can test x.ps1 on Linux diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile index 5219247cc6f..fb5037e3b97 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile @@ -25,6 +25,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ xz-utils \ nodejs \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* # Install powershell (universal package) so we can test x.ps1 on Linux diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 9c550b2d728..6fd113fcfd8 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.14.4 \ No newline at end of file +0.14.5 \ No newline at end of file diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 5b9581f72a6..fbec368c9ee 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config \ xz-utils \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index b490b766663..c594288dcf8 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -74,7 +74,7 @@ x--expand-yaml-anchors--remove: env: {} - &job-linux-xl - os: ubuntu-20.04-xl + os: ubuntu-20.04-16core-64gb <<: *base-job - &job-macos-xl @@ -82,7 +82,7 @@ x--expand-yaml-anchors--remove: <<: *base-job - &job-windows-xl - os: windows-latest-xl + os: windows-2019-8core-32gb <<: *base-job - &job-aarch64-linux diff --git a/src/ci/run.sh b/src/ci/run.sh index 93dccb54c4e..fc4ed57fb82 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -58,6 +58,15 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-native-static" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-units-std=1" +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set dist.compression-profile=best" + +# When building for mingw, limit the number of parallel linker jobs during +# the LLVM build, as not to run out of memory. +# This is an attempt to fix the spurious build error tracked by +# https://github.com/rust-lang/rust/issues/108227. +if isWindows && [[ ${CUSTOM_MINGW-0} -eq 1 ]]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.link-jobs=4" +fi # Only produce xz tarballs on CI. gz tarballs will be generated by the release # process by recompressing the existing xz ones. This decreases the storage diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index fe3083dc31e..d4d80e8f77c 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -175,8 +175,8 @@ class WindowsPipeline(Pipeline): return super().rustc_stage_2().with_suffix(".exe") def build_rustc_perf(self): - # rustc-perf version from 2022-07-22 - perf_commit = "3c253134664fdcba862c539d37f0de18557a9a4c" + # rustc-perf version from 2023-03-15 + perf_commit = "9dfaa35193154b690922347ee1141a06ec87a199" rustc_perf_zip_path = self.opt_artifacts() / "perf.zip" def download_rustc_perf(): diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index 28a004a9253..2957916d56c 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -80,13 +80,20 @@ functions, and "In Return Types" shows matches in the return types of functions. Both are very useful when looking for a function whose name you can't quite bring to mind when you know the type you have or want. -When typing in the search bar, you can prefix your search term with a type -followed by a colon (such as `mod:`) to restrict the results to just that -kind of item. (The available items are listed in the help popup.) - -Searching for `println!` will search for a macro named `println`, just like +Names in the search interface can be prefixed with an item type followed by a +colon (such as `mod:`) to restrict the results to just that kind of item. Also, +searching for `println!` will search for a macro named `println`, just like searching for `macro:println` does. +Function signature searches can query generics, wrapped in angle brackets, and +traits are normalized like types in the search engine. For example, a function +with the signature `fn my_function<I: Iterator<Item=u32>>(input: I) -> usize` +can be matched with the following queries: + +* `Iterator<u32> -> usize` +* `trait:Iterator<primitive:u32> -> primitive:usize` +* `Iterator -> usize` + ### Changing displayed theme You can change the displayed theme by opening the settings menu (the gear diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 262cef3454a..f71aceff455 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -213,7 +213,7 @@ See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details. ## Example -```text +```rust,ignore #![feature(naked_functions)] use std::arch::asm; @@ -238,7 +238,7 @@ pub extern "C" fn add_two(x: i32) { nop nop nop - lea rax, [rdi+2] + lea eax, [edi+2] ret ", options(noreturn) diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 6ca6edfd3c9..29912b95703 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -20,15 +20,13 @@ smallvec = "1.8.1" tempfile = "3" tracing = "0.1" tracing-tree = "0.2.0" +threadpool = "1.8.1" [dependencies.tracing-subscriber] version = "0.3.3" default-features = false features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] -[target.'cfg(windows)'.dependencies] -rayon = "1.5.1" - [dev-dependencies] expect-test = "1.4.0" diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index bcdbbcacc4b..3a3bf6a7ab9 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,6 +1,6 @@ use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_hir as hir; -use rustc_infer::infer::{InferOk, TyCtxtInferExt}; +use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits; use rustc_middle::ty::ToPredicate; use rustc_span::DUMMY_SP; @@ -47,8 +47,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { // Require the type the impl is implemented on to match // our type, and ignore the impl if there was a mismatch. - let cause = traits::ObligationCause::dummy(); - let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else { + let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, impl_trait_ref.self_ty(), impl_ty) else { continue }; let InferOk { value: (), obligations } = eq_result; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 148243683cb..768f8bb7bc8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -36,15 +36,11 @@ use crate::formats::item_type::ItemType; /// /// The returned value is `None` if the definition could not be inlined, /// and `Some` of a vector of items if it was successfully expanded. -/// -/// `parent_module` refers to the parent of the *re-export*, not the original item. pub(crate) fn try_inline( cx: &mut DocContext<'_>, - parent_module: DefId, - import_def_id: Option<DefId>, res: Res, name: Symbol, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option<DefId>)>, visited: &mut DefIdSet, ) -> Option<Vec<clean::Item>> { let did = res.opt_def_id()?; @@ -55,38 +51,17 @@ pub(crate) fn try_inline( debug!("attrs={:?}", attrs); - let attrs_without_docs = attrs.map(|attrs| { - attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>() + let attrs_without_docs = attrs.map(|(attrs, def_id)| { + (attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>(), def_id) }); - // We need this ugly code because: - // - // ``` - // attrs_without_docs.map(|a| a.as_slice()) - // ``` - // - // will fail because it returns a temporary slice and: - // - // ``` - // attrs_without_docs.map(|s| { - // vec = s.as_slice(); - // vec - // }) - // ``` - // - // will fail because we're moving an uninitialized variable into a closure. - let vec; - let attrs_without_docs = match attrs_without_docs { - Some(s) => { - vec = s; - Some(vec.as_slice()) - } - None => None, - }; + let attrs_without_docs = + attrs_without_docs.as_ref().map(|(attrs, def_id)| (&attrs[..], *def_id)); + let import_def_id = attrs.and_then(|(_, def_id)| def_id); let kind = match res { Res::Def(DefKind::Trait, did) => { record_extern_fqn(cx, did, ItemType::Trait); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::TraitItem(Box::new(build_external_trait(cx, did))) } Res::Def(DefKind::Fn, did) => { @@ -95,27 +70,27 @@ pub(crate) fn try_inline( } Res::Def(DefKind::Struct, did) => { record_extern_fqn(cx, did, ItemType::Struct); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::StructItem(build_struct(cx, did)) } Res::Def(DefKind::Union, did) => { record_extern_fqn(cx, did, ItemType::Union); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::UnionItem(build_union(cx, did)) } Res::Def(DefKind::TyAlias, did) => { record_extern_fqn(cx, did, ItemType::Typedef); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::TypedefItem(build_type_alias(cx, did)) } Res::Def(DefKind::Enum, did) => { record_extern_fqn(cx, did, ItemType::Enum); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::EnumItem(build_enum(cx, did)) } Res::Def(DefKind::ForeignTy, did) => { record_extern_fqn(cx, did, ItemType::ForeignType); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. @@ -149,7 +124,7 @@ pub(crate) fn try_inline( _ => return None, }; - let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs); + let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); cx.inlined.insert(did.into()); let mut item = clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg); @@ -316,9 +291,8 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::Typedef> /// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport. pub(crate) fn build_impls( cx: &mut DocContext<'_>, - parent_module: Option<DefId>, did: DefId, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option<DefId>)>, ret: &mut Vec<clean::Item>, ) { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls"); @@ -326,7 +300,7 @@ pub(crate) fn build_impls( // for each implementation of an item represented by `did`, build the clean::Item for that impl for &did in tcx.inherent_impls(did).iter() { - build_impl(cx, parent_module, did, attrs, ret); + build_impl(cx, did, attrs, ret); } // This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate. @@ -340,28 +314,26 @@ pub(crate) fn build_impls( let type_ = if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) }; for &did in tcx.incoherent_impls(type_) { - build_impl(cx, parent_module, did, attrs, ret); + build_impl(cx, did, attrs, ret); } } } -/// `parent_module` refers to the parent of the re-export, not the original item pub(crate) fn merge_attrs( cx: &mut DocContext<'_>, - parent_module: Option<DefId>, old_attrs: &[ast::Attribute], - new_attrs: Option<&[ast::Attribute]>, + new_attrs: Option<(&[ast::Attribute], Option<DefId>)>, ) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) { // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export // doc comments show up before the original doc comments // when we render them. - if let Some(inner) = new_attrs { + if let Some((inner, item_id)) = new_attrs { let mut both = inner.to_vec(); both.extend_from_slice(old_attrs); ( - if let Some(new_id) = parent_module { - Attributes::from_ast_with_additional(old_attrs, (inner, new_id)) + if let Some(item_id) = item_id { + Attributes::from_ast_with_additional(old_attrs, (inner, item_id)) } else { Attributes::from_ast(&both) }, @@ -375,9 +347,8 @@ pub(crate) fn merge_attrs( /// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`. pub(crate) fn build_impl( cx: &mut DocContext<'_>, - parent_module: Option<DefId>, did: DefId, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option<DefId>)>, ret: &mut Vec<clean::Item>, ) { if !cx.inlined.insert(did.into()) { @@ -539,7 +510,7 @@ pub(crate) fn build_impl( record_extern_trait(cx, did); } - let (merged_attrs, cfg) = merge_attrs(cx, parent_module, load_attrs(cx, did), attrs); + let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); trace!("merged_attrs={:?}", merged_attrs); trace!( @@ -635,7 +606,7 @@ fn build_module_items( cfg: None, inline_stmt_id: None, }); - } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) { + } else if let Some(i) = try_inline(cx, res, item.ident.name, None, visited) { items.extend(i) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 29c3afe0d95..c00fa5994bf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -39,6 +39,7 @@ use std::hash::Hash; use std::mem; use thin_vec::ThinVec; +use crate::clean::inline::merge_attrs; use crate::core::{self, DocContext, ImplTraitParam}; use crate::formats::item_type::ItemType; use crate::visit_ast::Module as DocModule; @@ -323,7 +324,7 @@ pub(crate) fn clean_predicate<'tcx>( ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::Subtype(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) @@ -426,7 +427,7 @@ fn clean_projection<'tcx>( cx: &mut DocContext<'tcx>, def_id: Option<DefId>, ) -> Type { - if cx.tcx.def_kind(ty.skip_binder().def_id) == DefKind::ImplTraitPlaceholder { + if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) { let bounds = cx .tcx .explicit_item_bounds(ty.skip_binder().def_id) @@ -2373,25 +2374,26 @@ fn clean_maybe_renamed_item<'tcx>( _ => unreachable!("not yet converted"), }; - let mut extra_attrs = Vec::new(); + let mut import_attrs = Vec::new(); + let mut target_attrs = Vec::new(); if let Some(import_id) = import_id && let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id) { let is_inline = inline::load_attrs(cx, import_id.to_def_id()).lists(sym::doc).get_word_attr(sym::inline).is_some(); // Then we get all the various imports' attributes. - get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs, is_inline); - add_without_unwanted_attributes(&mut extra_attrs, inline::load_attrs(cx, def_id), is_inline); + get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut import_attrs, is_inline); + add_without_unwanted_attributes(&mut target_attrs, inline::load_attrs(cx, def_id), is_inline); } else { // We only keep the item's attributes. - extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id)); + target_attrs.extend_from_slice(inline::load_attrs(cx, def_id)); } - let attrs = Attributes::from_ast(&extra_attrs); - let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); + let import_id = import_id.map(|def_id| def_id.to_def_id()); + let (attrs, cfg) = merge_attrs(cx, &target_attrs, Some((&import_attrs, import_id))); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg); - item.inline_stmt_id = import_id.map(|def_id| def_id.to_def_id()); + item.inline_stmt_id = import_id; vec![item] }) } @@ -2476,18 +2478,12 @@ fn clean_extern_crate<'tcx>( let krate_owner_def_id = krate.owner_id.to_def_id(); if please_inline { - let mut visited = DefIdSet::default(); - - let res = Res::Def(DefKind::Mod, crate_def_id); - if let Some(items) = inline::try_inline( cx, - cx.tcx.parent_module(krate.hir_id()).to_def_id(), - Some(krate_owner_def_id), - res, + Res::Def(DefKind::Mod, crate_def_id), name, - Some(attrs), - &mut visited, + Some((attrs, Some(krate_owner_def_id))), + &mut Default::default(), ) { return items; } @@ -2611,17 +2607,13 @@ fn clean_use_statement_inner<'tcx>( denied = true; } if !denied { - let mut visited = DefIdSet::default(); let import_def_id = import.owner_id.to_def_id(); - if let Some(mut items) = inline::try_inline( cx, - cx.tcx.parent_module(import.hir_id()).to_def_id(), - Some(import_def_id), path.res, name, - Some(attrs), - &mut visited, + Some((attrs, Some(import_def_id))), + &mut Default::default(), ) { items.push(Item::from_def_id_and_parts( import_def_id, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6d8380c5fcc..7dbb3f76a0a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1471,27 +1471,68 @@ impl Type { result } - /// Check if two types are "potentially the same". + pub(crate) fn is_borrowed_ref(&self) -> bool { + matches!(self, Type::BorrowedRef { .. }) + } + + /// Check if two types are "the same" for documentation purposes. + /// /// This is different from `Eq`, because it knows that things like /// `Placeholder` are possible matches for everything. - pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool { - match (self, other) { + /// + /// This relation is not commutative when generics are involved: + /// + /// ```ignore(private) + /// # // see types/tests.rs:is_same_generic for the real test + /// use rustdoc::format::cache::Cache; + /// use rustdoc::clean::types::{Type, PrimitiveType}; + /// let cache = Cache::new(false); + /// let generic = Type::Generic(rustc_span::symbol::sym::Any); + /// let unit = Type::Primitive(PrimitiveType::Unit); + /// assert!(!generic.is_same(&unit, &cache)); + /// assert!(unit.is_same(&generic, &cache)); + /// ``` + /// + /// An owned type is also the same as its borrowed variants (this is commutative), + /// but `&T` is not the same as `&mut T`. + pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool { + // Strip the references so that it can compare the actual types, unless both are references. + // If both are references, leave them alone and compare the mutabilities later. + let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() { + (self.without_borrowed_ref(), other.without_borrowed_ref()) + } else { + (self, other) + }; + match (self_cleared, other_cleared) { // Recursive cases. (Type::Tuple(a), Type::Tuple(b)) => { - a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache)) + a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache)) } - (Type::Slice(a), Type::Slice(b)) => a.is_same(b, cache), - (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(b, cache), + (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache), + (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache), (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => { - mutability == b_mutability && type_.is_same(b_type_, cache) + mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache) } ( Type::BorrowedRef { mutability, type_, .. }, Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. }, - ) => mutability == b_mutability && type_.is_same(b_type_, cache), - // Placeholders and generics are equal to all other types. + ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache), + // Placeholders are equal to all other types. (Type::Infer, _) | (_, Type::Infer) => true, - (Type::Generic(_), _) | (_, Type::Generic(_)) => true, + // Generics match everything on the right, but not on the left. + // If both sides are generic, this returns true. + (_, Type::Generic(_)) => true, + (Type::Generic(_), _) => false, + // Paths account for both the path itself and its generics. + (Type::Path { path: a }, Type::Path { path: b }) => { + a.def_id() == b.def_id() + && a.generics() + .zip(b.generics()) + .map(|(ag, bg)| { + ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)) + }) + .unwrap_or(true) + } // Other cases, such as primitives, just use recursion. (a, b) => a .def_id(cache) diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 20627c2cfc1..d8c91a96804 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -10,7 +10,7 @@ use rustc_span::symbol::Symbol; fn create_doc_fragment(s: &str) -> Vec<DocFragment> { vec![DocFragment { span: DUMMY_SP, - parent_module: None, + item_id: None, doc: Symbol::intern(s), kind: DocFragmentKind::SugaredDoc, indent: 0, @@ -69,3 +69,14 @@ fn should_not_trim() { run_test("\t line1 \n\t line2", "line1 \nline2"); run_test(" \tline1 \n \tline2", "line1 \nline2"); } + +#[test] +fn is_same_generic() { + use crate::clean::types::{PrimitiveType, Type}; + use crate::formats::cache::Cache; + let cache = Cache::new(false); + let generic = Type::Generic(rustc_span::symbol::sym::Any); + let unit = Type::Primitive(PrimitiveType::Unit); + assert!(!generic.is_doc_subtype_of(&unit, &cache)); + assert!(unit.is_doc_subtype_of(&generic, &cache)); +} diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index cafb00df51e..cca50df0db2 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -195,12 +195,12 @@ pub(crate) fn build_deref_target_impls( if let Some(prim) = target.primitive_type() { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); for did in prim.impls(tcx).filter(|did| !did.is_local()) { - inline::build_impl(cx, None, did, None, ret); + inline::build_impl(cx, did, None, ret); } } else if let Type::Path { path } = target { let did = path.def_id(); if !did.is_local() { - inline::build_impls(cx, None, did, None, ret); + inline::build_impls(cx, did, None, ret); } } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fbfc58a436b..28458f32903 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -217,13 +217,8 @@ pub(crate) fn create_config( let crate_types = if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] }; - let resolve_doc_links = if *document_private { - ResolveDocLinks::All - } else { - // Should be `ResolveDocLinks::Exported` in theory, but for some reason rustdoc - // still tries to request resolutions for links on private items. - ResolveDocLinks::All - }; + let resolve_doc_links = + if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported }; let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false); // plays with error output here! let sessopts = config::Options { diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs index be066bdafa1..d58b8dc6ad4 100644 --- a/src/librustdoc/docfs.rs +++ b/src/librustdoc/docfs.rs @@ -2,18 +2,20 @@ //! //! On Windows this indirects IO into threads to work around performance issues //! with Defender (and other similar virus scanners that do blocking operations). -//! On other platforms this is a thin shim to fs. //! //! Only calls needed to permit this workaround have been abstracted: thus //! fs::read is still done directly via the fs module; if in future rustdoc //! needs to read-after-write from a file, then it would be added to this //! abstraction. +use std::cmp::max; use std::fs; use std::io; use std::path::{Path, PathBuf}; use std::string::ToString; use std::sync::mpsc::Sender; +use std::thread::available_parallelism; +use threadpool::ThreadPool; pub(crate) trait PathError { fn new<S, P: AsRef<Path>>(e: S, path: P) -> Self @@ -24,11 +26,21 @@ pub(crate) trait PathError { pub(crate) struct DocFS { sync_only: bool, errors: Option<Sender<String>>, + pool: ThreadPool, } impl DocFS { pub(crate) fn new(errors: Sender<String>) -> DocFS { - DocFS { sync_only: false, errors: Some(errors) } + const MINIMUM_NB_THREADS: usize = 2; + DocFS { + sync_only: false, + errors: Some(errors), + pool: ThreadPool::new( + available_parallelism() + .map(|nb| max(nb.get(), MINIMUM_NB_THREADS)) + .unwrap_or(MINIMUM_NB_THREADS), + ), + } } pub(crate) fn set_sync_only(&mut self, sync_only: bool) { @@ -54,12 +66,11 @@ impl DocFS { where E: PathError, { - #[cfg(windows)] if !self.sync_only { // A possible future enhancement after more detailed profiling would // be to create the file sync so errors are reported eagerly. let sender = self.errors.clone().expect("can't write after closing"); - rayon::spawn(move || { + self.pool.execute(move || { fs::write(&path, contents).unwrap_or_else(|e| { sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| { panic!("failed to send error on \"{}\"", path.display()) @@ -70,9 +81,12 @@ impl DocFS { fs::write(&path, contents).map_err(|e| E::new(e, path))?; } - #[cfg(not(windows))] - fs::write(&path, contents).map_err(|e| E::new(e, path))?; - Ok(()) } } + +impl Drop for DocFS { + fn drop(&mut self) { + self.pool.join(); + } +} diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 9cf84acc79f..aaa83ecce48 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1057,6 +1057,16 @@ impl Tester for Collector { Ignore::Some(ref ignores) => ignores.iter().any(|s| target_str.contains(s)), }, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, // compiler failures are test failures should_panic: test::ShouldPanic::No, compile_fail: config.compile_fail, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 024ea62c31a..f2b9c0bcf3e 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -771,6 +771,12 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont .or_else(|| cache.external_paths.get(&did)) else { return String::new() }; let mut buf = Buffer::new(); + let fqp = if *shortty == ItemType::Primitive { + // primitives are documented in a crate, but not actually part of it + &fqp[fqp.len() - 1..] + } else { + &fqp + }; if let &Some(UrlFragment::Item(id)) = fragment { write!(buf, "{} ", cx.tcx().def_descr(id)); for component in fqp { @@ -1474,7 +1480,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( debug!("path={:?}", path); // modified from `resolved_path()` to work with `DefPathData` let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); - let anchor = anchor(vis_did, last_name, cx).to_string(); + let anchor = anchor(vis_did, last_name, cx); let mut s = "pub(in ".to_owned(); for seg in &path.data[..path.data.len() - 1] { @@ -1496,9 +1502,9 @@ pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>( tcx: TyCtxt<'tcx>, item_did: DefId, ) -> impl fmt::Display + 'a + Captures<'tcx> { - let to_print = match visibility { - None => String::new(), - Some(ty::Visibility::Public) => "pub ".to_owned(), + let to_print: Cow<'static, str> = match visibility { + None => "".into(), + Some(ty::Visibility::Public) => "pub ".into(), Some(ty::Visibility::Restricted(vis_did)) => { // FIXME(camelid): This may not work correctly if `item_did` is a module. // However, rustdoc currently never displays a module's @@ -1506,17 +1512,17 @@ pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>( let parent_module = find_nearest_parent_module(tcx, item_did); if vis_did.is_crate_root() { - "pub(crate) ".to_owned() + "pub(crate) ".into() } else if parent_module == Some(vis_did) { // `pub(in foo)` where `foo` is the parent module // is the same as no visibility modifier - String::new() + "".into() } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent)) == Some(vis_did) { - "pub(super) ".to_owned() + "pub(super) ".into() } else { - format!("pub(in {}) ", tcx.def_path_str(vis_did)) + format!("pub(in {}) ", tcx.def_path_str(vis_did)).into() } } }; diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 2c9fc4e3ca3..c099d0e4f3f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -65,23 +65,6 @@ pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) { write!(out, "</pre>"); } -/// Highlights `src` as a source code page, returning the HTML output. -pub(crate) fn render_source_with_highlighting( - src: &str, - out: &mut Buffer, - line_numbers: Buffer, - href_context: HrefContext<'_, '_>, - decoration_info: DecorationInfo, - extra: Option<&str>, -) { - write_header(out, "", Some(line_numbers), Tooltip::None); - if let Some(extra) = extra { - out.push_str(extra); - } - write_code(out, src, Some(href_context), Some(decoration_info)); - write_footer(out, None); -} - fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) { write!( out, @@ -143,8 +126,8 @@ fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool { /// This type is used as a conveniency to prevent having to pass all its fields as arguments into /// the various functions (which became its methods). -struct TokenHandler<'a, 'tcx> { - out: &'a mut Buffer, +struct TokenHandler<'a, 'tcx, F: Write> { + out: &'a mut F, /// It contains the closing tag and the associated `Class`. closing_tags: Vec<(&'static str, Class)>, /// This is used because we don't automatically generate the closing tag on `ExitSpan` in @@ -159,7 +142,7 @@ struct TokenHandler<'a, 'tcx> { href_context: Option<HrefContext<'a, 'tcx>>, } -impl<'a, 'tcx> TokenHandler<'a, 'tcx> { +impl<'a, 'tcx, F: Write> TokenHandler<'a, 'tcx, F> { fn handle_exit_span(&mut self) { // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is // being used in `write_pending_elems`. @@ -211,7 +194,7 @@ impl<'a, 'tcx> TokenHandler<'a, 'tcx> { } } -impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> { +impl<'a, 'tcx, F: Write> Drop for TokenHandler<'a, 'tcx, F> { /// When leaving, we need to flush all pending data to not have missing content. fn drop(&mut self) { if self.pending_exit_span.is_some() { @@ -233,8 +216,8 @@ impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> { /// item definition. /// /// More explanations about spans and how we use them here are provided in the -fn write_code( - out: &mut Buffer, +pub(super) fn write_code( + out: &mut impl Write, src: &str, href_context: Option<HrefContext<'_, '_>>, decoration_info: Option<DecorationInfo>, @@ -883,7 +866,7 @@ impl<'src> Classifier<'src> { /// Called when we start processing a span of text that should be highlighted. /// The `Class` argument specifies how it should be highlighted. fn enter_span( - out: &mut Buffer, + out: &mut impl Write, klass: Class, href_context: &Option<HrefContext<'_, '_>>, ) -> &'static str { @@ -894,8 +877,8 @@ fn enter_span( } /// Called at the end of a span of highlighted text. -fn exit_span(out: &mut Buffer, closing_tag: &str) { - out.write_str(closing_tag); +fn exit_span(out: &mut impl Write, closing_tag: &str) { + out.write_str(closing_tag).unwrap(); } /// Called for a span of text. If the text should be highlighted differently @@ -915,7 +898,7 @@ fn exit_span(out: &mut Buffer, closing_tag: &str) { /// will then try to find this `span` in the `span_correspondance_map`. If found, it'll then /// generate a link for this element (which corresponds to where its definition is located). fn string<T: Display>( - out: &mut Buffer, + out: &mut impl Write, text: T, klass: Option<Class>, href_context: &Option<HrefContext<'_, '_>>, @@ -923,7 +906,7 @@ fn string<T: Display>( ) { if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag) { - out.write_str(closing_tag); + out.write_str(closing_tag).unwrap(); } } @@ -937,7 +920,7 @@ fn string<T: Display>( /// in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's /// the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]). fn string_without_closing_tag<T: Display>( - out: &mut Buffer, + out: &mut impl Write, text: T, klass: Option<Class>, href_context: &Option<HrefContext<'_, '_>>, @@ -945,16 +928,16 @@ fn string_without_closing_tag<T: Display>( ) -> Option<&'static str> { let Some(klass) = klass else { - write!(out, "{}", text); + write!(out, "{}", text).unwrap(); return None; }; let Some(def_span) = klass.get_span() else { if !open_tag { - write!(out, "{}", text); + write!(out, "{}", text).unwrap(); return None; } - write!(out, "<span class=\"{}\">{}", klass.as_html(), text); + write!(out, "<span class=\"{}\">{}", klass.as_html(), text).unwrap(); return Some("</span>"); }; @@ -1009,28 +992,28 @@ fn string_without_closing_tag<T: Display>( if !open_tag { // We're already inside an element which has the same klass, no need to give it // again. - write!(out, "<a href=\"{}\">{}", href, text_s); + write!(out, "<a href=\"{}\">{}", href, text_s).unwrap(); } else { let klass_s = klass.as_html(); if klass_s.is_empty() { - write!(out, "<a href=\"{}\">{}", href, text_s); + write!(out, "<a href=\"{}\">{}", href, text_s).unwrap(); } else { - write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s); + write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s).unwrap(); } } return Some("</a>"); } } if !open_tag { - write!(out, "{}", text_s); + write!(out, "{}", text_s).unwrap(); return None; } let klass_s = klass.as_html(); if klass_s.is_empty() { - write!(out, "{}", text_s); + out.write_str(&text_s).unwrap(); Some("") } else { - write!(out, "<span class=\"{}\">{}", klass_s, text_s); + write!(out, "<span class=\"{}\">{}", klass_s, text_s).unwrap(); Some("</span>") } } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index fe446ae3c16..fd81a21f5a9 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -556,7 +556,15 @@ fn check_if_allowed_tag(t: &Tag<'_>) -> bool { } fn is_forbidden_tag(t: &Tag<'_>) -> bool { - matches!(t, Tag::CodeBlock(_) | Tag::Table(_) | Tag::TableHead | Tag::TableRow | Tag::TableCell) + matches!( + t, + Tag::CodeBlock(_) + | Tag::Table(_) + | Tag::TableHead + | Tag::TableRow + | Tag::TableCell + | Tag::FootnoteDefinition(_) + ) } impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> { @@ -589,6 +597,10 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> { is_start = false; check_if_allowed_tag(c) } + Event::FootnoteReference(_) => { + self.skipped_tags += 1; + false + } _ => true, }; if !is_allowed_tag { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 63cd0e04a28..ac5054ce1b6 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -352,7 +352,7 @@ impl<'tcx> Context<'tcx> { }, ); - path = href.into_inner().to_string_lossy().to_string(); + path = href.into_inner().to_string_lossy().into_owned(); if let Some(c) = path.as_bytes().last() && *c != b'/' { path.push('/'); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index da1f1cf5ecc..d75d03071f8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1294,7 +1294,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; @@ -1330,7 +1330,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { for i in impls { let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 577497868f6..579b5a9c723 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1,5 +1,6 @@ use clean::AttributesExt; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -28,8 +29,8 @@ use crate::formats::item_type::ItemType; use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ - join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause, - visibility_print_with_space, Buffer, Ending, PrintWithSpace, + display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space, + print_where_clause, visibility_print_with_space, Buffer, Ending, PrintWithSpace, }; use crate::html::layout::Page; use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; @@ -367,7 +368,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: ..myitem.clone() }; - let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx())); + let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()).to_string()); stab_tags } else { None @@ -461,42 +462,62 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: /// Render the stability, deprecation and portability tags that are displayed in the item's summary /// at the module level. -fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> String { - let mut tags = String::new(); - - fn tag_html(class: &str, title: &str, contents: &str) -> String { - format!(r#"<span class="stab {}" title="{}">{}</span>"#, class, Escape(title), contents) - } - - // The trailing space after each tag is to space it properly against the rest of the docs. - if let Some(depr) = &item.deprecation(tcx) { - let message = if stability::deprecation_in_effect(depr) { - "Deprecated" - } else { - "Deprecation planned" - }; - tags += &tag_html("deprecated", "", message); - } +fn extra_info_tags<'a, 'tcx: 'a>( + item: &'a clean::Item, + parent: &'a clean::Item, + tcx: TyCtxt<'tcx>, +) -> impl fmt::Display + 'a + Captures<'tcx> { + display_fn(move |f| { + fn tag_html<'a>( + class: &'a str, + title: &'a str, + contents: &'a str, + ) -> impl fmt::Display + 'a { + display_fn(move |f| { + write!( + f, + r#"<span class="stab {}" title="{}">{}</span>"#, + class, + Escape(title), + contents + ) + }) + } - // The "rustc_private" crates are permanently unstable so it makes no sense - // to render "unstable" everywhere. - if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private) - == Some(true) - { - tags += &tag_html("unstable", "", "Experimental"); - } + // The trailing space after each tag is to space it properly against the rest of the docs. + if let Some(depr) = &item.deprecation(tcx) { + let message = if stability::deprecation_in_effect(depr) { + "Deprecated" + } else { + "Deprecation planned" + }; + write!(f, "{}", tag_html("deprecated", "", message))?; + } - let cfg = match (&item.cfg, parent.cfg.as_ref()) { - (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), - (cfg, _) => cfg.as_deref().cloned(), - }; + // The "rustc_private" crates are permanently unstable so it makes no sense + // to render "unstable" everywhere. + if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private) + == Some(true) + { + write!(f, "{}", tag_html("unstable", "", "Experimental"))?; + } - debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg); - if let Some(ref cfg) = cfg { - tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()); - } + let cfg = match (&item.cfg, parent.cfg.as_ref()) { + (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), + (cfg, _) => cfg.as_deref().cloned(), + }; - tags + debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg); + if let Some(ref cfg) = cfg { + write!( + f, + "{}", + tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()) + ) + } else { + Ok(()) + } + }) } fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) { @@ -859,8 +880,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter().partition(|i| i.inner_impl().kind.is_auto()); - synthetic.sort_by(|a, b| compare_impl(a, b, cx)); - concrete.sort_by(|a, b| compare_impl(a, b, cx)); + synthetic.sort_by_cached_key(|i| ImplString::new(i, cx)); + concrete.sort_by_cached_key(|i| ImplString::new(i, cx)); if !foreign.is_empty() { write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); @@ -1576,12 +1597,25 @@ where w.write_str("</code></pre>"); } -fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cx: &Context<'_>) -> Ordering { - let lhss = format!("{}", lhs.inner_impl().print(false, cx)); - let rhss = format!("{}", rhs.inner_impl().print(false, cx)); +#[derive(PartialEq, Eq)] +struct ImplString(String); - // lhs and rhs are formatted as HTML, which may be unnecessary - compare_names(&lhss, &rhss) +impl ImplString { + fn new(i: &Impl, cx: &Context<'_>) -> ImplString { + ImplString(format!("{}", i.inner_impl().print(false, cx))) + } +} + +impl PartialOrd for ImplString { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for ImplString { + fn cmp(&self, other: &Self) -> Ordering { + compare_names(&self.0, &other.0) + } } fn render_implementor( diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 146221f5806..08a0e1c377e 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -486,7 +486,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( } // First, check if it's "Self". - let arg = if let Some(self_) = self_ { + let mut arg = if let Some(self_) = self_ { match &*arg { Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_, type_ if type_.is_self_type() => self_, @@ -496,11 +496,16 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( arg }; + // strip references from the argument type + while let Type::BorrowedRef { type_, .. } = &*arg { + arg = &*type_; + } + // If this argument is a type parameter and not a trait bound or a type, we need to look // for its bounds. if let Type::Generic(arg_s) = *arg { // First we check if the bounds are in a `where` predicate... - if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g { + for where_pred in generics.where_predicates.iter().filter(|g| match g { WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s, _ => false, }) { diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 2c90bf4fadc..1d298f52f75 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -1,12 +1,14 @@ use crate::clean; use crate::docfs::PathError; use crate::error::Error; +use crate::html::format; use crate::html::format::Buffer; use crate::html::highlight; use crate::html::layout; use crate::html::render::Context; use crate::visit::DocVisitor; +use askama::Template; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; @@ -16,6 +18,7 @@ use rustc_span::source_map::FileName; use std::cell::RefCell; use std::ffi::OsStr; use std::fs; +use std::ops::RangeInclusive; use std::path::{Component, Path, PathBuf}; use std::rc::Rc; @@ -85,7 +88,7 @@ impl LocalSourcesCollector<'_, '_> { }, ); - let mut href = href.into_inner().to_string_lossy().to_string(); + let mut href = href.into_inner().to_string_lossy().into_owned(); if let Some(c) = href.as_bytes().last() && *c != b'/' { href.push('/'); } @@ -299,39 +302,32 @@ pub(crate) fn print_src( decoration_info: highlight::DecorationInfo, source_context: SourceContext, ) { + #[derive(Template)] + #[template(path = "source.html")] + struct Source<Code: std::fmt::Display> { + embedded: bool, + needs_expansion: bool, + lines: RangeInclusive<usize>, + code_html: Code, + } let lines = s.lines().count(); - let mut line_numbers = Buffer::empty_from(buf); - let extra; - line_numbers.write_str("<pre class=\"src-line-numbers\">"); + let (embedded, needs_expansion, lines) = match source_context { + SourceContext::Standalone => (false, false, 1..=lines), + SourceContext::Embedded { offset, needs_expansion } => { + (true, needs_expansion, (1 + offset)..=(lines + offset)) + } + }; let current_href = context .href_from_span(clean::Span::new(file_span), false) .expect("only local crates should have sources emitted"); - match source_context { - SourceContext::Standalone => { - extra = None; - for line in 1..=lines { - writeln!(line_numbers, "<a href=\"#{line}\" id=\"{line}\">{line}</a>") - } - } - SourceContext::Embedded { offset, needs_expansion } => { - extra = if needs_expansion { - Some(r#"<button class="expand">↕</button>"#) - } else { - None - }; - for line_number in 1..=lines { - let line = line_number + offset; - writeln!(line_numbers, "<span>{line}</span>") - } - } - } - line_numbers.write_str("</pre>"); - highlight::render_source_with_highlighting( - s, - buf, - line_numbers, - highlight::HrefContext { context, file_span, root_path, current_href }, - decoration_info, - extra, - ); + let code = format::display_fn(move |fmt| { + highlight::write_code( + fmt, + s, + Some(highlight::HrefContext { context, file_span, root_path, current_href }), + Some(decoration_info), + ); + Ok(()) + }); + Source { embedded, needs_expansion, lines, code_html: code }.render_into(buf).unwrap(); } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 95528e70e35..7d578b5c775 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -217,7 +217,7 @@ ul.all-items { a.anchor, .small-section-header a, #source-sidebar a, -pre.rust a, +.rust a, .sidebar h2 a, .sidebar h3 a, .mobile-topbar h2 a, @@ -228,43 +228,43 @@ h1 a, color: var(--main-color); } -.content span.enum, .content a.enum, -.content span.struct, .content a.struct, -.content span.union, .content a.union, -.content span.primitive, .content a.primitive, -.content span.type, .content a.type, -.content span.foreigntype, .content a.foreigntype { +span.enum, a.enum, +span.struct, a.struct, +span.union, a.union, +span.primitive, a.primitive, +span.type, a.type, +span.foreigntype, a.foreigntype { color: var(--type-link-color); } -.content span.trait, .content a.trait, -.content span.traitalias, .content a.traitalias { +span.trait, a.trait, +span.traitalias, a.traitalias { color: var(--trait-link-color); } -.content span.associatedtype, .content a.associatedtype, -.content span.constant, .content a.constant, -.content span.static, .content a.static { +span.associatedtype, a.associatedtype, +span.constant, a.constant, +span.static, a.static { color: var(--assoc-item-link-color); } -.content span.fn, .content a.fn, -.content span.method, .content a.method, -.content span.tymethod, .content a.tymethod { +span.fn, a.fn, +span.method, a.method, +span.tymethod, a.tymethod { color: var(--function-link-color); } -.content span.attr, .content a.attr, -.content span.derive, .content a.derive, -.content span.macro, .content a.macro { +span.attr, a.attr, +span.derive, a.derive, +span.macro, a.macro { color: var(--macro-link-color); } -.content span.mod, .content a.mod { +span.mod, a.mod { color: var(--mod-link-color); } -.content span.keyword, .content a.keyword { +span.keyword, a.keyword { color: var(--keyword-link-color); } @@ -713,7 +713,7 @@ h2.small-section-header > .anchor { } .main-heading a:hover, -.example-wrap > pre.rust a:hover, +.example-wrap > .rust a:hover, .all-items a:hover, .docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, .docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index c71ce2c3001..840ed8e1080 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -354,12 +354,15 @@ function initSearch(rawSearchIndex) { if (isInGenerics) { parserState.genericsElems += 1; } + const typeFilter = parserState.typeFilter; + parserState.typeFilter = null; return { name: name, fullPath: pathSegments, pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1), pathLast: pathSegments[pathSegments.length - 1], generics: generics, + typeFilter, }; } @@ -495,6 +498,11 @@ function initSearch(rawSearchIndex) { */ function getItemsBefore(query, parserState, elems, endChar) { let foundStopChar = true; + let start = parserState.pos; + + // If this is a generic, keep the outer item's type filter around. + const oldTypeFilter = parserState.typeFilter; + parserState.typeFilter = null; while (parserState.pos < parserState.length) { const c = parserState.userQuery[parserState.pos]; @@ -506,7 +514,25 @@ function initSearch(rawSearchIndex) { continue; } else if (c === ":" && isPathStart(parserState)) { throw ["Unexpected ", "::", ": paths cannot start with ", "::"]; - } else if (c === ":" || isEndCharacter(c)) { + } else if (c === ":") { + if (parserState.typeFilter !== null) { + throw ["Unexpected ", ":"]; + } + if (elems.length === 0) { + throw ["Expected type filter before ", ":"]; + } else if (query.literalSearch) { + throw ["You cannot use quotes on type filter"]; + } + // The type filter doesn't count as an element since it's a modifier. + const typeFilterElem = elems.pop(); + checkExtraTypeFilterCharacters(start, parserState); + parserState.typeFilter = typeFilterElem.name; + parserState.pos += 1; + parserState.totalElems -= 1; + query.literalSearch = false; + foundStopChar = true; + continue; + } else if (isEndCharacter(c)) { let extra = ""; if (endChar === ">") { extra = "<"; @@ -540,15 +566,10 @@ function initSearch(rawSearchIndex) { ]; } const posBefore = parserState.pos; + start = parserState.pos; getNextElem(query, parserState, elems, endChar === ">"); - if (endChar !== "") { - if (parserState.pos >= parserState.length) { - throw ["Unclosed ", "<"]; - } - const c2 = parserState.userQuery[parserState.pos]; - if (!isSeparatorCharacter(c2) && c2 !== endChar) { - throw ["Expected ", endChar, ", found ", c2]; - } + if (endChar !== "" && parserState.pos >= parserState.length) { + throw ["Unclosed ", "<"]; } // This case can be encountered if `getNextElem` encountered a "stop character" right // from the start. For example if you have `,,` or `<>`. In this case, we simply move up @@ -564,6 +585,8 @@ function initSearch(rawSearchIndex) { // We are either at the end of the string or on the `endChar` character, let's move forward // in any case. parserState.pos += 1; + + parserState.typeFilter = oldTypeFilter; } /** @@ -572,10 +595,10 @@ function initSearch(rawSearchIndex) { * * @param {ParserState} parserState */ - function checkExtraTypeFilterCharacters(parserState) { + function checkExtraTypeFilterCharacters(start, parserState) { const query = parserState.userQuery; - for (let pos = 0; pos < parserState.pos; ++pos) { + for (let pos = start; pos < parserState.pos; ++pos) { if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) { throw ["Unexpected ", query[pos], " in type filter"]; } @@ -591,6 +614,7 @@ function initSearch(rawSearchIndex) { */ function parseInput(query, parserState) { let foundStopChar = true; + let start = parserState.pos; while (parserState.pos < parserState.length) { const c = parserState.userQuery[parserState.pos]; @@ -612,16 +636,15 @@ function initSearch(rawSearchIndex) { } if (query.elems.length === 0) { throw ["Expected type filter before ", ":"]; - } else if (query.elems.length !== 1 || parserState.totalElems !== 1) { - throw ["Unexpected ", ":"]; } else if (query.literalSearch) { throw ["You cannot use quotes on type filter"]; } - checkExtraTypeFilterCharacters(parserState); // The type filter doesn't count as an element since it's a modifier. - parserState.typeFilter = query.elems.pop().name; + const typeFilterElem = query.elems.pop(); + checkExtraTypeFilterCharacters(start, parserState); + parserState.typeFilter = typeFilterElem.name; parserState.pos += 1; - parserState.totalElems = 0; + parserState.totalElems -= 1; query.literalSearch = false; foundStopChar = true; continue; @@ -653,6 +676,7 @@ function initSearch(rawSearchIndex) { ]; } const before = query.elems.length; + start = parserState.pos; getNextElem(query, parserState, query.elems, false); if (query.elems.length === before) { // Nothing was added, weird... Let's increase the position to not remain stuck. @@ -660,6 +684,9 @@ function initSearch(rawSearchIndex) { } foundStopChar = false; } + if (parserState.typeFilter !== null) { + throw ["Unexpected ", ":", " (expected path after type filter)"]; + } while (parserState.pos < parserState.length) { if (isReturnArrow(parserState)) { parserState.pos += 2; @@ -687,7 +714,6 @@ function initSearch(rawSearchIndex) { return { original: userQuery, userQuery: userQuery.toLowerCase(), - typeFilter: NO_TYPE_FILTER, elems: [], returned: [], // Total number of "top" elements (does not include generics). @@ -738,8 +764,8 @@ function initSearch(rawSearchIndex) { * * ident = *(ALPHA / DIGIT / "_") * path = ident *(DOUBLE-COLON ident) [!] - * arg = path [generics] - * arg-without-generic = path + * arg = [type-filter *WS COLON *WS] path [generics] + * arg-without-generic = [type-filter *WS COLON *WS] path * type-sep = COMMA/WS *(COMMA/WS) * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep) * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic @@ -749,7 +775,7 @@ function initSearch(rawSearchIndex) { * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list * * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ] - * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ] + * type-search = [ nonempty-arg-list ] [ return-args ] * * query = *WS (exact-search / type-search) *WS * @@ -798,6 +824,20 @@ function initSearch(rawSearchIndex) { * @return {ParsedQuery} - The parsed query */ function parseQuery(userQuery) { + function convertTypeFilterOnElem(elem) { + if (elem.typeFilter !== null) { + let typeFilter = elem.typeFilter; + if (typeFilter === "const") { + typeFilter = "constant"; + } + elem.typeFilter = itemTypeFromName(typeFilter); + } else { + elem.typeFilter = NO_TYPE_FILTER; + } + for (const elem2 of elem.generics) { + convertTypeFilterOnElem(elem2); + } + } userQuery = userQuery.trim(); const parserState = { length: userQuery.length, @@ -812,17 +852,15 @@ function initSearch(rawSearchIndex) { try { parseInput(query, parserState); - if (parserState.typeFilter !== null) { - let typeFilter = parserState.typeFilter; - if (typeFilter === "const") { - typeFilter = "constant"; - } - query.typeFilter = itemTypeFromName(typeFilter); + for (const elem of query.elems) { + convertTypeFilterOnElem(elem); + } + for (const elem of query.returned) { + convertTypeFilterOnElem(elem); } } catch (err) { query = newParsedQuery(userQuery); query.error = err; - query.typeFilter = -1; return query; } @@ -1057,12 +1095,10 @@ function initSearch(rawSearchIndex) { } // The names match, but we need to be sure that all generics kinda // match as well. - let elem_name; if (elem.generics.length > 0 && row.generics.length >= elem.generics.length) { const elems = Object.create(null); for (const entry of row.generics) { - elem_name = entry.name; - if (elem_name === "") { + if (entry.name === "") { // Pure generic, needs to check into it. if (checkGenerics(entry, elem, maxEditDistance + 1, maxEditDistance) !== 0) { @@ -1070,19 +1106,19 @@ function initSearch(rawSearchIndex) { } continue; } - if (elems[elem_name] === undefined) { - elems[elem_name] = 0; + if (elems[entry.name] === undefined) { + elems[entry.name] = []; } - elems[elem_name] += 1; + elems[entry.name].push(entry.ty); } // We need to find the type that matches the most to remove it in order // to move forward. - for (const generic of elem.generics) { + const handleGeneric = generic => { let match = null; if (elems[generic.name]) { match = generic.name; } else { - for (elem_name in elems) { + for (const elem_name in elems) { if (!hasOwnPropertyRustdoc(elems, elem_name)) { continue; } @@ -1093,12 +1129,32 @@ function initSearch(rawSearchIndex) { } } if (match === null) { - return maxEditDistance + 1; + return false; + } + const matchIdx = elems[match].findIndex(tmp_elem => + typePassesFilter(generic.typeFilter, tmp_elem)); + if (matchIdx === -1) { + return false; } - elems[match] -= 1; - if (elems[match] === 0) { + elems[match].splice(matchIdx, 1); + if (elems[match].length === 0) { delete elems[match]; } + return true; + }; + // To do the right thing with type filters, we first process generics + // that have them, removing matching ones from the "bag," then do the + // ones with no type filter, which can match any entry regardless of its + // own type. + for (const generic of elem.generics) { + if (generic.typeFilter !== -1 && !handleGeneric(generic)) { + return maxEditDistance + 1; + } + } + for (const generic of elem.generics) { + if (generic.typeFilter === -1 && !handleGeneric(generic)) { + return maxEditDistance + 1; + } } return 0; } @@ -1145,14 +1201,20 @@ function initSearch(rawSearchIndex) { return maxEditDistance + 1; } - let dist = editDistance(row.name, elem.name, maxEditDistance); + let dist; + if (typePassesFilter(elem.typeFilter, row.ty)) { + dist = editDistance(row.name, elem.name, maxEditDistance); + } else { + dist = maxEditDistance + 1; + } if (literalSearch) { if (dist !== 0) { // The name didn't match, let's try to check if the generics do. if (elem.generics.length === 0) { const checkGeneric = row.generics.length > 0; if (checkGeneric && row.generics - .findIndex(tmp_elem => tmp_elem.name === elem.name) !== -1) { + .findIndex(tmp_elem => tmp_elem.name === elem.name && + typePassesFilter(elem.typeFilter, tmp_elem.ty)) !== -1) { return 0; } } @@ -1201,29 +1263,42 @@ function initSearch(rawSearchIndex) { * * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. - * @param {integer} typeFilter + * @param {integer} maxEditDistance + * @param {Array<integer>} skipPositions - Do not return one of these positions. * - * @return {integer} - Returns an edit distance to the best match. If there is no - * match, returns `maxEditDistance + 1`. + * @return {dist: integer, position: integer} - Returns an edit distance to the best match. + * If there is no match, returns + * `maxEditDistance + 1` and position: -1. */ - function findArg(row, elem, typeFilter, maxEditDistance) { + function findArg(row, elem, maxEditDistance, skipPositions) { let dist = maxEditDistance + 1; + let position = -1; if (row && row.type && row.type.inputs && row.type.inputs.length > 0) { + let i = 0; for (const input of row.type.inputs) { - if (!typePassesFilter(typeFilter, input.ty)) { + if (skipPositions.indexOf(i) !== -1) { + i += 1; continue; } - dist = Math.min( - dist, - checkType(input, elem, parsedQuery.literalSearch, maxEditDistance) + const typeDist = checkType( + input, + elem, + parsedQuery.literalSearch, + maxEditDistance ); - if (dist === 0) { - return 0; + if (typeDist === 0) { + return {dist: 0, position: i}; + } + if (typeDist < dist) { + dist = typeDist; + position = i; } + i += 1; } } - return parsedQuery.literalSearch ? maxEditDistance + 1 : dist; + dist = parsedQuery.literalSearch ? maxEditDistance + 1 : dist; + return {dist, position}; } /** @@ -1231,30 +1306,43 @@ function initSearch(rawSearchIndex) { * * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. - * @param {integer} typeFilter + * @param {integer} maxEditDistance + * @param {Array<integer>} skipPositions - Do not return one of these positions. * - * @return {integer} - Returns an edit distance to the best match. If there is no - * match, returns `maxEditDistance + 1`. + * @return {dist: integer, position: integer} - Returns an edit distance to the best match. + * If there is no match, returns + * `maxEditDistance + 1` and position: -1. */ - function checkReturned(row, elem, typeFilter, maxEditDistance) { + function checkReturned(row, elem, maxEditDistance, skipPositions) { let dist = maxEditDistance + 1; + let position = -1; if (row && row.type && row.type.output.length > 0) { const ret = row.type.output; + let i = 0; for (const ret_ty of ret) { - if (!typePassesFilter(typeFilter, ret_ty.ty)) { + if (skipPositions.indexOf(i) !== -1) { + i += 1; continue; } - dist = Math.min( - dist, - checkType(ret_ty, elem, parsedQuery.literalSearch, maxEditDistance) + const typeDist = checkType( + ret_ty, + elem, + parsedQuery.literalSearch, + maxEditDistance ); - if (dist === 0) { - return 0; + if (typeDist === 0) { + return {dist: 0, position: i}; } + if (typeDist < dist) { + dist = typeDist; + position = i; + } + i += 1; } } - return parsedQuery.literalSearch ? maxEditDistance + 1 : dist; + dist = parsedQuery.literalSearch ? maxEditDistance + 1 : dist; + return {dist, position}; } function checkPath(contains, ty, maxEditDistance) { @@ -1455,15 +1543,15 @@ function initSearch(rawSearchIndex) { const fullId = row.id; const searchWord = searchWords[pos]; - const in_args = findArg(row, elem, parsedQuery.typeFilter, maxEditDistance); - const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxEditDistance); + const in_args = findArg(row, elem, maxEditDistance, []); + const returned = checkReturned(row, elem, maxEditDistance, []); // path_dist is 0 because no parent path information is currently stored // in the search index - addIntoResults(results_in_args, fullId, pos, -1, in_args, 0, maxEditDistance); - addIntoResults(results_returned, fullId, pos, -1, returned, 0, maxEditDistance); + addIntoResults(results_in_args, fullId, pos, -1, in_args.dist, 0, maxEditDistance); + addIntoResults(results_returned, fullId, pos, -1, returned.dist, 0, maxEditDistance); - if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) { + if (!typePassesFilter(elem.typeFilter, row.ty)) { return; } @@ -1534,12 +1622,19 @@ function initSearch(rawSearchIndex) { // If the result is too "bad", we return false and it ends this search. function checkArgs(elems, callback) { + const skipPositions = []; for (const elem of elems) { // There is more than one parameter to the query so all checks should be "exact" - const dist = callback(row, elem, NO_TYPE_FILTER, maxEditDistance); + const { dist, position } = callback( + row, + elem, + maxEditDistance, + skipPositions + ); if (dist <= 1) { nbDist += 1; totalDist += dist; + skipPositions.push(position); } else { return false; } @@ -1596,10 +1691,17 @@ function initSearch(rawSearchIndex) { in_returned = checkReturned( row, elem, - parsedQuery.typeFilter, + maxEditDistance, + [] + ); + addIntoResults( + results_others, + row.id, + i, + -1, + in_returned.dist, maxEditDistance ); - addIntoResults(results_others, row.id, i, -1, in_returned, maxEditDistance); } } } else if (parsedQuery.foundElems > 0) { diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md index 72c516c93eb..0281b1c47f8 100644 --- a/src/librustdoc/html/templates/STYLE.md +++ b/src/librustdoc/html/templates/STYLE.md @@ -1,12 +1,12 @@ # Style for Templates -This directory has templates in the [Tera templating language](teradoc), which is very -similar to [Jinja2](jinjadoc) and [Django](djangodoc) templates, and also to [Askama](askamadoc). +This directory has templates in the [Tera templating language][teradoc], which is very +similar to [Jinja2][jinjadoc] and [Django][djangodoc] templates, and also to [Askama][askamadoc]. [teradoc]: https://tera.netlify.app/docs/#templates -[jinjadoc]: https://jinja.palletsprojects.com/en/3.0.x/templates/ -[djangodoc]: https://docs.djangoproject.com/en/3.2/topics/templates/ -[askamadoc]: https://docs.rs/askama/0.10.5/askama/ +[jinjadoc]: https://jinja.palletsprojects.com/en/3.1.x/templates/ +[djangodoc]: https://docs.djangoproject.com/en/4.1/topics/templates/ +[askamadoc]: https://docs.rs/askama/latest/askama/ We want our rendered output to have as little unnecessary whitespace as possible, so that pages load quickly. To achieve that we use Tera's @@ -30,8 +30,8 @@ contents don't necessarily need a new line. Askama templates support quite sophisticated control flow. To keep our templates simple and understandable, we use only a subset: `if` and `for`. In particular -we avoid [assignments in the template logic](assignments) and [Askama -macros](macros). This also may make things easier if we switch to a different +we avoid [assignments in the template logic][assignments] and [Askama +macros][macros]. This also may make things easier if we switch to a different Jinja-style template system, like Askama, in the future. [assignments]: https://djc.github.io/askama/template_syntax.html#assignments diff --git a/src/librustdoc/html/templates/short_item_info.html b/src/librustdoc/html/templates/short_item_info.html index e3125af0e47..75d155e91c2 100644 --- a/src/librustdoc/html/templates/short_item_info.html +++ b/src/librustdoc/html/templates/short_item_info.html @@ -2,7 +2,7 @@ {% when Self::Deprecation with { message } %} <div class="stab deprecated"> {# #} <span class="emoji">👎</span> {# #} - <span>{{message}}</span> {# #} + <span>{{message|safe}}</span> {# #} </div> {# #} {% when Self::Unstable with { feature, tracking } %} <div class="stab unstable"> {# #} diff --git a/src/librustdoc/html/templates/source.html b/src/librustdoc/html/templates/source.html new file mode 100644 index 00000000000..a224ff12f44 --- /dev/null +++ b/src/librustdoc/html/templates/source.html @@ -0,0 +1,19 @@ +<div class="example-wrap"> {# #} + <pre class="src-line-numbers"> + {% for line in lines.clone() %} + {% if embedded %} + <span>{{line|safe}}</span> + {%~ else %} + <a href="#{{line|safe}}" id="{{line|safe}}">{{line|safe}}</a> + {%~ endif %} + {% endfor %} + </pre> {# #} + <pre class="rust"> {# #} + <code> + {% if needs_expansion %} + <button class="expand">↕</button> + {% endif %} + {{code_html|safe}} + </code> {# #} + </pre> {# #} +</div> diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 358f6ad566c..d98cf251e97 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -15,8 +15,8 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::Mutability; use rustc_middle::ty::{fast_reject::TreatProjections, Ty, TyCtxt}; use rustc_middle::{bug, ty}; -use rustc_resolve::rustdoc::MalformedGenerics; -use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, strip_generics_from_path}; +use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution}; +use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics}; use rustc_session::lint::Lint; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -28,7 +28,7 @@ use std::mem; use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module}; -use crate::clean::{Crate, Item, ItemId, ItemLink, PrimitiveType}; +use crate::clean::{Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; use crate::html::markdown::{markdown_links, MarkdownLink}; use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; @@ -42,8 +42,7 @@ pub(crate) const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut collector = - LinkCollector { cx, mod_ids: Vec::new(), visited_links: FxHashMap::default() }; + let mut collector = LinkCollector { cx, visited_links: FxHashMap::default() }; collector.visit_crate(&krate); krate } @@ -149,7 +148,7 @@ impl TryFrom<ResolveRes> for Res { #[derive(Debug)] struct UnresolvedPath<'a> { /// Item on which the link is resolved, used for resolving `Self`. - item_id: ItemId, + item_id: DefId, /// The scope the link was resolved in. module_id: DefId, /// If part of the link resolved, this has the `Res`. @@ -225,7 +224,7 @@ impl UrlFragment { #[derive(Clone, Debug, Hash, PartialEq, Eq)] struct ResolutionInfo { - item_id: ItemId, + item_id: DefId, module_id: DefId, dis: Option<Disambiguator>, path_str: Box<str>, @@ -242,11 +241,6 @@ struct DiagnosticInfo<'a> { struct LinkCollector<'a, 'tcx> { cx: &'a mut DocContext<'tcx>, - /// A stack of modules used to decide what scope to resolve in. - /// - /// The last module will be used if the parent scope of the current item is - /// unknown. - mod_ids: Vec<DefId>, /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link. /// The link will be `None` if it could not be resolved (i.e. the error was cached). visited_links: FxHashMap<ResolutionInfo, Option<(Res, Option<UrlFragment>)>>, @@ -262,7 +256,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn variant_field<'path>( &self, path_str: &'path str, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Result<(Res, DefId), UnresolvedPath<'path>> { let tcx = self.cx.tcx; @@ -286,7 +280,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { split.next().map(|f| Symbol::intern(f)).ok_or_else(no_res)?; let path = split .next() - .map(|f| f.to_owned()) // If there's no third component, we saw `[a::b]` before and it failed to resolve. // So there's no partial res. .ok_or_else(no_res)?; @@ -334,35 +327,33 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) } - fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Option<Res> { + fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option<Res> { if ns != TypeNS || path_str != "Self" { return None; } let tcx = self.cx.tcx; - item_id - .as_def_id() - .map(|def_id| match tcx.def_kind(def_id) { - def_kind @ (DefKind::AssocFn - | DefKind::AssocConst - | DefKind::AssocTy - | DefKind::Variant - | DefKind::Field) => { - let parent_def_id = tcx.parent(def_id); - if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant - { - tcx.parent(parent_def_id) - } else { - parent_def_id - } + let self_id = match tcx.def_kind(item_id) { + def_kind @ (DefKind::AssocFn + | DefKind::AssocConst + | DefKind::AssocTy + | DefKind::Variant + | DefKind::Field) => { + let parent_def_id = tcx.parent(item_id); + if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant { + tcx.parent(parent_def_id) + } else { + parent_def_id } - _ => def_id, - }) - .and_then(|self_id| match tcx.def_kind(self_id) { - DefKind::Impl { .. } => self.def_id_to_res(self_id), - DefKind::Use => None, - def_kind => Some(Res::Def(def_kind, self_id)), - }) + } + _ => item_id, + }; + + match tcx.def_kind(self_id) { + DefKind::Impl { .. } => self.def_id_to_res(self_id), + DefKind::Use => None, + def_kind => Some(Res::Def(def_kind, self_id)), + } } /// Convenience wrapper around `doc_link_resolutions`. @@ -374,7 +365,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &self, path_str: &str, ns: Namespace, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Option<Res> { if let res @ Some(..) = self.resolve_self_ty(path_str, ns, item_id) { @@ -401,7 +392,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &mut self, path_str: &'path str, ns: Namespace, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Result<(Res, Option<DefId>), UnresolvedPath<'path>> { if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) { @@ -429,7 +420,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let item_name = Symbol::intern(item_str); let path_root = split .next() - .map(|f| f.to_owned()) // If there's no `::`, it's not an associated item. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. .ok_or_else(|| { @@ -781,48 +771,8 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { fn visit_item(&mut self, item: &Item) { - let parent_node = - item.item_id.as_def_id().and_then(|did| find_nearest_parent_module(self.cx.tcx, did)); - if parent_node.is_some() { - trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.item_id); - } - - let inner_docs = item.inner_docs(self.cx.tcx); - - if item.is_mod() && inner_docs { - self.mod_ids.push(item.item_id.expect_def_id()); - } - - // We want to resolve in the lexical scope of the documentation. - // In the presence of re-exports, this is not the same as the module of the item. - // Rather than merging all documentation into one, resolve it one attribute at a time - // so we know which module it came from. - for (parent_module, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { - if !may_have_doc_links(&doc) { - continue; - } - debug!("combined_docs={}", doc); - // NOTE: if there are links that start in one crate and end in another, this will not resolve them. - // This is a degenerate case and it's not supported by rustdoc. - let parent_node = parent_module.or(parent_node); - for md_link in preprocessed_markdown_links(&doc) { - let link = self.resolve_link(item, &doc, parent_node, &md_link); - if let Some(link) = link { - self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link); - } - } - } - - if item.is_mod() { - if !inner_docs { - self.mod_ids.push(item.item_id.expect_def_id()); - } - - self.visit_item_recur(item); - self.mod_ids.pop(); - } else { - self.visit_item_recur(item) - } + self.resolve_links(item); + self.visit_item_recur(item) } } @@ -948,14 +898,50 @@ fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> { } impl LinkCollector<'_, '_> { + fn resolve_links(&mut self, item: &Item) { + if !self.cx.render_options.document_private + && let Some(def_id) = item.item_id.as_def_id() + && let Some(def_id) = def_id.as_local() + && !self.cx.tcx.effective_visibilities(()).is_exported(def_id) + && !has_primitive_or_keyword_docs(&item.attrs.other_attrs) { + // Skip link resolution for non-exported items. + return; + } + + // We want to resolve in the lexical scope of the documentation. + // In the presence of re-exports, this is not the same as the module of the item. + // Rather than merging all documentation into one, resolve it one attribute at a time + // so we know which module it came from. + for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { + if !may_have_doc_links(&doc) { + continue; + } + debug!("combined_docs={}", doc); + // NOTE: if there are links that start in one crate and end in another, this will not resolve them. + // This is a degenerate case and it's not supported by rustdoc. + let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); + let module_id = match self.cx.tcx.def_kind(item_id) { + DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id, + _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), + }; + for md_link in preprocessed_markdown_links(&doc) { + let link = self.resolve_link(item, item_id, module_id, &doc, &md_link); + if let Some(link) = link { + self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link); + } + } + } + } + /// This is the entry point for resolving an intra-doc link. /// /// FIXME(jynelson): this is way too many arguments fn resolve_link( &mut self, item: &Item, + item_id: DefId, + module_id: DefId, dox: &str, - parent_node: Option<DefId>, link: &PreprocessedMarkdownLink, ) -> Option<ItemLink> { let PreprocessedMarkdownLink(pp_link, ori_link) = link; @@ -972,25 +958,9 @@ impl LinkCollector<'_, '_> { pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?; let disambiguator = *disambiguator; - // In order to correctly resolve intra-doc links we need to - // pick a base AST node to work from. If the documentation for - // this module came from an inner comment (//!) then we anchor - // our name resolution *inside* the module. If, on the other - // hand it was an outer comment (///) then we anchor the name - // resolution in the parent module on the basis that the names - // used are more likely to be intended to be parent names. For - // this, we set base_node to None for inner comments since - // we've already pushed this node onto the resolution stack but - // for outer comments we explicitly try and resolve against the - // parent_node first. - let inner_docs = item.inner_docs(self.cx.tcx); - let base_node = - if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node }; - let module_id = base_node.expect("doc link without parent module"); - let (mut res, fragment) = self.resolve_with_disambiguator_cached( ResolutionInfo { - item_id: item.item_id, + item_id, module_id, dis: disambiguator, path_str: path_str.clone(), @@ -1231,11 +1201,11 @@ impl LinkCollector<'_, '_> { let disambiguator = key.dis; let path_str = &key.path_str; let item_id = key.item_id; - let base_node = key.module_id; + let module_id = key.module_id; match disambiguator.map(Disambiguator::ns) { Some(expected_ns) => { - match self.resolve(path_str, expected_ns, item_id, base_node) { + match self.resolve(path_str, expected_ns, item_id, module_id) { Ok(res) => Some(res), Err(err) => { // We only looked in one namespace. Try to give a better error if possible. @@ -1245,7 +1215,7 @@ impl LinkCollector<'_, '_> { for other_ns in [TypeNS, ValueNS, MacroNS] { if other_ns != expected_ns { if let Ok(res) = - self.resolve(path_str, other_ns, item_id, base_node) + self.resolve(path_str, other_ns, item_id, module_id) { err = ResolutionFailure::WrongNamespace { res: full_res(self.cx.tcx, res), @@ -1262,7 +1232,7 @@ impl LinkCollector<'_, '_> { None => { // Try everything! let mut candidate = |ns| { - self.resolve(path_str, ns, item_id, base_node) + self.resolve(path_str, ns, item_id, module_id) .map_err(ResolutionFailure::NotResolved) }; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index d32e8185d3f..8d204ddb79e 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -49,7 +49,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls"); for &cnum in cx.tcx.crates(()) { for &impl_def_id in cx.tcx.trait_impls_in_crate(cnum) { - inline::build_impl(cx, None, impl_def_id, None, &mut new_items_external); + inline::build_impl(cx, impl_def_id, None, &mut new_items_external); } } } @@ -75,7 +75,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> ); parent = cx.tcx.opt_parent(did); } - inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local); + inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local); attr_buf.clear(); } } @@ -84,7 +84,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> for def_id in PrimitiveType::all_impls(cx.tcx) { // Try to inline primitive impls from other crates. if !def_id.is_local() { - inline::build_impl(cx, None, def_id, None, &mut new_items_external); + inline::build_impl(cx, def_id, None, &mut new_items_external); } } for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) { diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index f35643af637..8a33e51b3be 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -57,7 +57,8 @@ impl<'a, 'tcx> CfgPropagator<'a, 'tcx> { next_def_id = parent_def_id; } - let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs)); + let (_, cfg) = + merge_attrs(self.cx, item.attrs.other_attrs.as_slice(), Some((&attrs, None))); item.cfg = cfg; } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index e09a68069e8..060062db002 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -265,10 +265,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } - if !self.view_item_stack.insert(res_did) { - return false; - } - if !please_inline && let mut visitor = OneLevelVisitor::new(self.cx.tcx.hir(), res_did) && let Some(item) = visitor.find_target(self.cx.tcx, def_id.to_def_id(), path) && @@ -285,6 +281,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } + if !self.view_item_stack.insert(res_did) { + return false; + } + let ret = match tcx.hir().get_by_def_id(res_did) { Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); diff --git a/src/stage0.json b/src/stage0.json index 46f70b1ef4b..9250d9c2804 100644 --- a/src/stage0.json +++ b/src/stage0.json @@ -17,409 +17,409 @@ "tool is executed." ], "compiler": { - "date": "2023-01-25", + "date": "2023-03-07", "version": "beta" }, "rustfmt": { - "date": "2023-01-30", + "date": "2023-03-07", "version": "nightly" }, "checksums_sha256": { - "dist/2023-01-25/cargo-beta-aarch64-apple-darwin.tar.gz": "323f3c4c41892765b24201aae83a54fcaef08e47b9b2912a2680528c6ed4f8f8", - "dist/2023-01-25/cargo-beta-aarch64-apple-darwin.tar.xz": "2039157d9100ccadf4d3596f5d7b052e10ff997b59ac7619999969794fc51eae", - "dist/2023-01-25/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "ac3c88c99aed8d4547f8b0f857ec3538456f10223411580278eed10f6e2be30b", - "dist/2023-01-25/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "27b11ea3c67f202e61b5e7394d36bedc7f1b054ca53d68e53ccd7bacf77b4af3", - "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "4d6d1d47d34e8042aa978fe5a6b5b8984d6626d38731081db2d5b413d5b844f4", - "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "a50e473aa6b6bffd84a719aec602d4bc19f03ccb0ee5f26340eb466501cb2970", - "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "a043def73a5c72d515c3d7dabe09022c353b047e7a4e4e13e9b17da9b30f8828", - "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "a63a8915409df4ae5d76d530b46cb7e83b6e6ca79790fa095d899e33773124a0", - "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "9c0c413187f1f1e0f1b6f1b66af0bd1b264d94f73439f6df24f476ee1c6c04fe", - "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "cb79e76beb989a3e4ffd1461817ad2dd0602aca3bce1a2e54cccc1bbb518a303", - "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "d57c5806a13b498768b53a053c7eb17e8becb19ea5fc9561a2a600dafea32056", - "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "33f35d8c2f5fcd5fa7928f2186a8b2417040e01462152430bae978d8d5a661cd", - "dist/2023-01-25/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "80ba79da61f82dc760a9dd7bfdfde29fefcab4ae94917cbf5d908332f93061d3", - "dist/2023-01-25/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "a8e48c6345b0e195ea58d6237a247b0d20c8d128af1b12813430806b9a340d5b", - "dist/2023-01-25/cargo-beta-i686-pc-windows-gnu.tar.gz": "052e2c0ff954d66e40101dc075bdd19fdb0befcbfdbc26dd94093bc4147c65cc", - "dist/2023-01-25/cargo-beta-i686-pc-windows-gnu.tar.xz": "94681fbbeb12de4b97b0a5a0206204c41b16c3de1c7c3262e1488f00b22aeb51", - "dist/2023-01-25/cargo-beta-i686-pc-windows-msvc.tar.gz": "3c0c2205e97136ac5e13b3c89d745af24afc60e6b5adc24abf22755d8d0007a1", - "dist/2023-01-25/cargo-beta-i686-pc-windows-msvc.tar.xz": "9ccf1a81d524fbac3f859c0185421936b97ae565164c12ed32e6a39052eac695", - "dist/2023-01-25/cargo-beta-i686-unknown-linux-gnu.tar.gz": "68749447a45ada6bb6e06488e3d58ecca7939d3c77dc40c22f22d7257eae247c", - "dist/2023-01-25/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6b8942c01d1b8fd1f1f399b7f63db409a30df240b5aca5cf34e3166adafb5053", - "dist/2023-01-25/cargo-beta-mips-unknown-linux-gnu.tar.gz": "7f8fcf5d25353dac5d2cd6ad04b20da19b2dbccd25a977e8122d85724a632392", - "dist/2023-01-25/cargo-beta-mips-unknown-linux-gnu.tar.xz": "91d0ec836e2941287ac28a753650e1b7b57364af58fdfedebe1fafea8612f1ac", - "dist/2023-01-25/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "171f40046f777d84fe5a4349d3565ad3485fdf075d8fbe194ca31ba2be9eeb1a", - "dist/2023-01-25/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0521be760b2a1e6cc134bbe3473dea01a6d0fbf68b05995f41a75875d489eb60", - "dist/2023-01-25/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "ee7c39af31d09a42c5ce1151da6dc1147b5c1aceb0ea94cb3059bac49e72ba2a", - "dist/2023-01-25/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "dc8ddfc8bd305c3f1f4d7965b8bbd8b24235ef758c38a32b3d64b5879fab25d2", - "dist/2023-01-25/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "4757229750f44b3d523ef7a9c778d923113a8eb8b93ad97ef5e4f23a6f1e6a21", - "dist/2023-01-25/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "36911ebbdde86d90bca90b61b1b31f6ab054ff65907ac73a22d5ae09d061c444", - "dist/2023-01-25/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "8e4ce0a0743d301d056a1bafb4216ae96fd6cb06ca083216eaf7f3a21514e064", - "dist/2023-01-25/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "47e28a41670bbcc7a3787c68dcf72ffe42bfbc3e9f14418871ca814538f88180", - "dist/2023-01-25/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "7bcab6e25cd8208eb220839f6adb202dcd382e4bc32fa63b83c40fba330246b9", - "dist/2023-01-25/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "650bb4d6b51ef5293164642101395fbf6d9eedcaccccc8ff3e2be032d9e60316", - "dist/2023-01-25/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "fc779f539835c1f3e1e7d9c1eed932568a5e731888f766202279e9240dd20e36", - "dist/2023-01-25/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "b39ab17c34560266df7dc60b6cf5626758f8b28f7142b916f1f3399342e6e0ec", - "dist/2023-01-25/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "7b677b4a2cc59b3baebc1265f8a364879b2195905de1eb20f62b66e2fbfdbb08", - "dist/2023-01-25/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bceab89d3ae1ffd25fc155a7b3514c69e3962ce8f7727cc7e7c4b40f0c6eb3eb", - "dist/2023-01-25/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "d0522064a1994aa338d12f5ef68635f8804a2cb9151dd67771ae132e65560790", - "dist/2023-01-25/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "478fdff509a609e5310c54fa1e0eecbb3870a0636132dbcc71291e150c805828", - "dist/2023-01-25/cargo-beta-x86_64-apple-darwin.tar.gz": "cfb5bc9dcf4c85915e5c7e4a29e7f45c4e5de4a3535c75ce7c192c08511e0350", - "dist/2023-01-25/cargo-beta-x86_64-apple-darwin.tar.xz": "6b1f48ceebc916f9829f599fc815de2b8724873ce8a22ba058a2a1ac1df46295", - "dist/2023-01-25/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "60d119c084899f0a1d7661188756833118bc538d7e7298c72d1452b06e27ef62", - "dist/2023-01-25/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "801d03dfab7e8007a97d95c551b3a069e56371fe33fa4682e20fa50a8123bc20", - "dist/2023-01-25/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "269bdb128749d234e12b5795b90acc1a91bc0c338ed3be70ab2e62d476fcd055", - "dist/2023-01-25/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "88737cc19187a0752e45345eb286a5e9d500f9c71e03bb26737888fe42b350b5", - "dist/2023-01-25/cargo-beta-x86_64-unknown-freebsd.tar.gz": "146d1af37cce4b6eff9f99bb74ad33f2d91383a2b69dfdbd59ad54fc2dd44c49", - "dist/2023-01-25/cargo-beta-x86_64-unknown-freebsd.tar.xz": "9466a4417a1ea6a9ab03ea7d05f747a731ed0bf5545148a1c782c797dcff50a9", - "dist/2023-01-25/cargo-beta-x86_64-unknown-illumos.tar.gz": "f32fcd8a18047646865afc67f92d6edda54fbe3f4e9963aba2095e23295e6ce0", - "dist/2023-01-25/cargo-beta-x86_64-unknown-illumos.tar.xz": "25431bfe87d8c944225122d21ca4823cefe72b304b10933c628d5d2df13d5f5c", - "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "cd67e483efd3a9cca57523cee428cd9a5555ff93b057f7fef4178a3e2fd49309", - "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "45d578c09399495b67ac38358e4251e3d7a20e988428a1a5a1e39387d2664da8", - "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "f66eb2cf2c637b4822e2c326b4a57d63eb3c0b517ddb69ff57a45001bc0a110f", - "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "7a0817ef29d6511d4fd9dbbdf3e9a92635f076d9b0633cb55b325cebeee4efb9", - "dist/2023-01-25/cargo-beta-x86_64-unknown-netbsd.tar.gz": "1330a1b4f975b1d96692bdc4a6392ca87e8e99982768acefc2815e386b6f4e77", - "dist/2023-01-25/cargo-beta-x86_64-unknown-netbsd.tar.xz": "919e25bd54133f4a8cbbf09218415ca7a5041298b32181fa566c5d4a8bfd8b90", - "dist/2023-01-25/rust-std-beta-aarch64-apple-darwin.tar.gz": "3dcf5c58141e44d1c84f33f58ca4dd99edd277ef15a69fc6b94fbe7c67a27483", - "dist/2023-01-25/rust-std-beta-aarch64-apple-darwin.tar.xz": "a651af6487e2f3246075b984fffb4072338a559ff8e6c373289a6242c0ca3ea7", - "dist/2023-01-25/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "5e3d5aa50784ee63c6df03b07ac92649f76c40ac6fb49c24d97896814002697c", - "dist/2023-01-25/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "0ae7440c74cee87c25757159a5749014eecf77b2bcee7e1e71eb9249f917d725", - "dist/2023-01-25/rust-std-beta-aarch64-apple-ios.tar.gz": "a47acbecb37786773c5d80da5990298c5facad11151c9991796eedf80472b1d5", - "dist/2023-01-25/rust-std-beta-aarch64-apple-ios.tar.xz": "9168f9b1cea16a213249a1c452a59719234c145045ddc6ae1752ce4bdf02be41", - "dist/2023-01-25/rust-std-beta-aarch64-linux-android.tar.gz": "54fad0afeead88e1f33eaada03b14710052c6fa0b7130dd87463d3670f1d9fb3", - "dist/2023-01-25/rust-std-beta-aarch64-linux-android.tar.xz": "5fdd761ca88de80754cf3e1221db141204f79e6c2aa57c72c0879af3b87dd0f4", - "dist/2023-01-25/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "27196acc8f1ab9d6843b673835927c16d6730a8daf96b1f05959884ac53232fe", - "dist/2023-01-25/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "0ea12b5fade681173aa4795399710cf5ff21d58f5f2fe54eb8d2c7516ef387b8", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "7bd0d57ba438868635726bad30fea7a52a5c429e77329bf2977805872deb1be2", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "8520674b4e10a6948b25dc0c58369e921a68c48a7b961bae510ac36e5c29cfe8", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "67c5668ce3427245821e53ea976201ebc23d1cb3c1a35a0d725d935de303e8a6", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "38236c5e562995e1aadd25151513580a2a7c7828df3baec0e0cccc0f6a856c2a", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "a5453d21e3620701a957208c573d718872c3909c2c4f9e83be33e14d36677cda", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "751928d0f640e3b77e2fde9cda623c3e9b3bca7de742100fc1f48388e4d22d8d", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "5a036c4d9cbda730e6f2af8c4912506659d1e3065b4d72050cc5b18e442105ea", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "2adfb04a0700dd3503527a80eb5ee71733b0fa2dbe974650d450d4bc3b5c8b0e", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-none.tar.gz": "a92fa3278a98de5ab93d1f487863453dbe60bb31158d027aaaef85adf1f62924", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-none.tar.xz": "1c0e523505aa9dbc07ec867ff8527dde29a706868bb55694d62e31924429e235", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-uefi.tar.gz": "4adaac4b13c8d8170b59913230ac9e313ae48400b314d2ce10c138631626728e", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-uefi.tar.xz": "2a2178e4e55f35ea5147f66d36450f9694416c0fbae9b776f39f405a1ab31cbb", - "dist/2023-01-25/rust-std-beta-arm-linux-androideabi.tar.gz": "17e4384d3a229bc452897e26400016c70912feb7e6ac2991a256829c5b391148", - "dist/2023-01-25/rust-std-beta-arm-linux-androideabi.tar.xz": "e57afb560be9a93faf5f0f852eac5cf5b16e2c05383d995a4e6a249367ee4567", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "d5a7c8f2fd9c3a1baa573b805334e5446605d2aa4589262f67e321c0590ef19e", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "1e62c48781111afd20fb1e015a4f611c3a3301762fd9e64e49beeb6f2bd14c8d", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "9e62d990466900818533af63479758f01f6e914d6ccb7910639c6fbbd49ae803", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "e685b0f2acf33c2eb58ac1e1a526787ee9df2f0bd1a1850581cc681c41a3ef0e", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "7a02618c26f17076add562a9f8792d170fe60190d1868703936e37df3af882e4", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "d8988dd528dcc19742b703d44dff4ebcef71cec66eaae39768434d77e53557eb", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "882e8f09cf68f135a29e64d0eb50727e4ac56939c4cfbcc3d369b928be442099", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "7d9b1ebaf89cad6024f07543519dde11da15eab0e2de3df88543156e4a44c48f", - "dist/2023-01-25/rust-std-beta-armebv7r-none-eabi.tar.gz": "a7e73661652b1feb9b1f50d271ebeba2938c169c8add96add8a26ded3d8468f5", - "dist/2023-01-25/rust-std-beta-armebv7r-none-eabi.tar.xz": "2a80ab44cb2f2b9769f52b6ddc5ffa4c8994092b18a7fb3125cdfaecb4e1a578", - "dist/2023-01-25/rust-std-beta-armebv7r-none-eabihf.tar.gz": "f70b0f86c783cc771700dc1f59c43e53b0de2d57775fef5854cd97fde4406b11", - "dist/2023-01-25/rust-std-beta-armebv7r-none-eabihf.tar.xz": "07214e7295be853fc7859481fcf94a4b20cc3bc2c022bf1783ddea56e30f92de", - "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "72be8b0740b14edda6656d2b5cffc69dea01f9bad7fcc9202586a901376116b2", - "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "42fb2607f1c7402f4d32be981cb5c0755be2e36fd0296b3b2753eecae98e5cc3", - "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "ae9ec6f3c3444e5b14103db8c04b95597705fe44c68c253c75383b47da4094de", - "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "1e0f7f1ccf9e4f6cc010a096d01f3e6056f1d4b0d319f5699dc67cad2f889d4a", - "dist/2023-01-25/rust-std-beta-armv7-linux-androideabi.tar.gz": "6e8b70d2606902b369dfc263ee25343fa3c71c4081f03066822e9a2a260ac573", - "dist/2023-01-25/rust-std-beta-armv7-linux-androideabi.tar.xz": "e3f9052bc831ca0a9b38a3da3be846113c6ab2c4f320ecdba489f0eddfc7e47c", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "e858e836806f3641c2f1074e63ce88771cdf135bca36d7c0d3dec0d1a4c98f8e", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "becfe9addbca5bf2123d12e70007c16c036c79fb299de2ce8da067d0f21b0f74", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eef38b595752add74cf3bd29326116e33a0945115d08ced77e603c5bb46e72c0", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "77e5cf7b344e590b9a15b2c160473f7c212304f624ed9aea8c7a8fd5e0fd787c", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "2a70ffd7f8f3289e005c0f72e2c127a44f8f014628df7ac01b4b0ae2fc61a9c9", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "97e2ae0072d5ae01644eda9a0c3438e78da27bb2f78d843fd626d3db36a6090b", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "7a30075e86bbd33241120dcf078b31ca9ec1877788db2c5700f4752cd447b587", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "2c1dfbc1361f030a3a116936f3e43e2c3adae2529feffc98a76e78fdad3572d9", - "dist/2023-01-25/rust-std-beta-armv7a-none-eabi.tar.gz": "aafe7ae2fc49e2c4ae9e1e008700f399f397dfca05d624dac4999f6c733ae2cb", - "dist/2023-01-25/rust-std-beta-armv7a-none-eabi.tar.xz": "d4bde0e0db35cb07134f6a94eee24e4359478dec9054e8a3802440eed68f60b7", - "dist/2023-01-25/rust-std-beta-armv7r-none-eabi.tar.gz": "fe83fe1f0b051838767589ecc9c17915441a44cd77226c9be26e9a63951bce2c", - "dist/2023-01-25/rust-std-beta-armv7r-none-eabi.tar.xz": "94eee8d1125537ebe1002c424c686c50996c03ed31d0a1275d49fd7ef0420ae1", - "dist/2023-01-25/rust-std-beta-armv7r-none-eabihf.tar.gz": "6ea9fca06fdb82026505c85a7bf7ad8be01926096be63c6cf20c5625c42df7dd", - "dist/2023-01-25/rust-std-beta-armv7r-none-eabihf.tar.xz": "70459483493bbb4cb2cc4b2af0cb012c01c47afc214643a588cf894a028a0ceb", - "dist/2023-01-25/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "27d86df76c05de73d0ff9542d6904f03ecbd2cedd3a9d6a9cb654dcb78363514", - "dist/2023-01-25/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "24b5a81721fe20849bdf075d39a99c0e80a21178327f9fa96b21649c99486213", - "dist/2023-01-25/rust-std-beta-i586-pc-windows-msvc.tar.gz": "3740517ab4573f77d5812c9b9c04fe63eacd29e56ea7ba5c5f335ad66026bd30", - "dist/2023-01-25/rust-std-beta-i586-pc-windows-msvc.tar.xz": "6c4e780249dcf8b306f8fab3fddd232724248b2670113dfc14c7823781d669f5", - "dist/2023-01-25/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "15fc95314219ac5b38f44a4ec3568fbb4ce66d7ff7b63cdf1fb7a8b058f2933c", - "dist/2023-01-25/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "b1a5ffd05afd400760002da124a8e5c86d091db574bf1ccf255d86b2515789e8", - "dist/2023-01-25/rust-std-beta-i586-unknown-linux-musl.tar.gz": "ef3551edc72cb79e776c7792346352eb858f3e3f7ee1c261b47ef974e52d9a2f", - "dist/2023-01-25/rust-std-beta-i586-unknown-linux-musl.tar.xz": "0e1a8e0ababab458af0a329e14398274fa55bf0e6ce2b2a0a515e5f6d12d6f34", - "dist/2023-01-25/rust-std-beta-i686-linux-android.tar.gz": "74a26b7fee3e0b95f4f0e065bcac58b865abd5f9abe14e42b2263bb0b87aee69", - "dist/2023-01-25/rust-std-beta-i686-linux-android.tar.xz": "c7df97d2322f5f331d349e35091ab5a61fae8dfc16781f1a74849c7c1e150293", - "dist/2023-01-25/rust-std-beta-i686-pc-windows-gnu.tar.gz": "396ca6747252adc4e6d41764df00418de22c22ee77823836c4fa3f1bd7cae869", - "dist/2023-01-25/rust-std-beta-i686-pc-windows-gnu.tar.xz": "4536de17560a21d543f81f6bdb25581a3b145b792531590a6ba35464e95c6389", - "dist/2023-01-25/rust-std-beta-i686-pc-windows-msvc.tar.gz": "da11b2338bacffa3940497b20fbb2544c0846696925d59cf9d7cf4514dedbb81", - "dist/2023-01-25/rust-std-beta-i686-pc-windows-msvc.tar.xz": "5bd5cd665f9e3d92f26998694c12b1f0e53df8ca9ef305c4cc48dd81bbe181f8", - "dist/2023-01-25/rust-std-beta-i686-unknown-freebsd.tar.gz": "b1553f92e0d0891717635136ad698a017c6aaab07a58183284752ff5480b37bf", - "dist/2023-01-25/rust-std-beta-i686-unknown-freebsd.tar.xz": "d6d2a550d36028e5adf62b875fccbae2f78546828de880e5bea33effca22edbd", - "dist/2023-01-25/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "3d9f9c3108d45f95ebd12c284147111155cd3714caa555548111fb6791c7ef1b", - "dist/2023-01-25/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "a4d9ee2238037d3ca5d4a9dd51c04737ecc2a12dc0be1e2996bbe46d7c1cebb9", - "dist/2023-01-25/rust-std-beta-i686-unknown-linux-musl.tar.gz": "9380bbf6ac2d745d1b7c3207c2cdacdd7bef0ff225e3ee5f22e46d826835b17a", - "dist/2023-01-25/rust-std-beta-i686-unknown-linux-musl.tar.xz": "517232f4e831f5305e836cc0666adef721c1b68fae80617a57bfb56405e343b9", - "dist/2023-01-25/rust-std-beta-i686-unknown-uefi.tar.gz": "1e6bfe0d160e3650a1a453de57f51673a6e04f9348f361fe08d2e96fa89d058c", - "dist/2023-01-25/rust-std-beta-i686-unknown-uefi.tar.xz": "f19c1458ef1386540cffca6cf7485ad22c38f0e9ee8a62e26a4e10eeeddb2a36", - "dist/2023-01-25/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "6169b653843ce79f799a99fc7f147bf8315688214dc47a64aed792f5ca274ffa", - "dist/2023-01-25/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "7f5e0f0e02c51dd88b9b819d1ae370e922eacf2523dd0ae664cbd8d79b7cdffe", - "dist/2023-01-25/rust-std-beta-mips-unknown-linux-musl.tar.gz": "124c50ad3ca4da2c97a5e96599762d7fad6701d0193b4a1ba3249c3a67d349ab", - "dist/2023-01-25/rust-std-beta-mips-unknown-linux-musl.tar.xz": "0a07005e369def1cbc8d49cd2904a1fd60c23771eca700e9b4abc49d2edf74a6", - "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "5278c6eab22d49d033595f8b98cccfcb89fa8827ef3a8ce487e78c9f74452d2b", - "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "206a55c0e4fb54ccfe2f372888bf42212352d56a7f1b3ba6628aec130b325573", - "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "f64069192d200f852e82735e239cb678fae027a7120e9d79c136aa4a3887bdb1", - "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "b31af554724c4582494548efda53dbef35db5cd3609104550ab2eee1bcb3f327", - "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "8445183d07e397b5bcd0f45fbb1b58ff22dc0901d0a1a3637761929f6b0e0364", - "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "5919f229d0ca138205def6752109056c989493c3a2a241cbd891bfdd84f8c7f0", - "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "c72e51c7b1a5720dd74a923fc2ce1caaff1da484c063b50f96bcf84db529326f", - "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "9a11cb1d587e2389531edff732c205a653e43bc62132cf697cb9fd04842558df", - "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "682fe8fe1e3dad08190e8c42fb2df8fc734a42df081c59d0b30f4cc9f5fcef8d", - "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7eee1fff997cd847aac8d6c61cad4bc572d3069dbe59ce2a06c39d6b63346d34", - "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "0b5c68bb95668394dda1c910cf99835007271b5598d4652c7c6b974c6c0b2acd", - "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "411c8552901b80720a3bca0707eef475a7ad1650d34cda0b29fedfa9fc9b1852", - "dist/2023-01-25/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "187fef84302125e38937cf390bdf26d40ef98c6d06fd5893db8adceab3e75f04", - "dist/2023-01-25/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "83ce613db91a23549e4a1e1d5e4c24ad3ca7ddfb586b45d25e2bd85e67a19390", - "dist/2023-01-25/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "785bdd67b22af15637696a03b6a4a917f8195049a4bda14a88dc48e6c3101a5e", - "dist/2023-01-25/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "df034c1d2baea51f6756e1efef58db81cda5e795691c3a7175cb3b61edd8f33a", - "dist/2023-01-25/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "24d020c96db72a49c39dca1546a683d4d2134718dafbd74fb846dc77b30cf78e", - "dist/2023-01-25/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "a798a58bf5723f86b08a11c92f901cee246c5a0af06c4f7e08b303c7fd6c0354", - "dist/2023-01-25/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0c383e01f53b5bf85301c46978493e94aef2eba98a966ea283771de7829ea492", - "dist/2023-01-25/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "61040426e2eb9950a3487109977ebfe66c134f5394c95847df222ff24c61563b", - "dist/2023-01-25/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "ef44851d420b5ee0cc3351084c9bc645e4caba447c8dd737840315687547657d", - "dist/2023-01-25/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "5cb083baabc7f33c515f2dbdaafd49465c85888d97af68dbd2bcd08a3e70e016", - "dist/2023-01-25/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "96bd2d16b470e6377c9c2894b24e77d9f7b51dd54d5369dc361791153a9d1519", - "dist/2023-01-25/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "93af94b167327c431158be466ff47b3aab8a77319bf7bed8bdbdedb4633a8e67", - "dist/2023-01-25/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "57071d1f70a444a1b4b26b2a579e6c6324522893de60be9e97fe281e8878f276", - "dist/2023-01-25/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "a75b8cbf062d1c6fcd8b2089c83f82b75247ced44793272ec56849c4448389f9", - "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "195fe88c1b4b77cb12f566e27a9d3ff25ed2edf5f26be9b3b3dd0a88ac6f5e3c", - "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "76884a90032874b98b0f4f873818dd90befc91d2ed96945120a1ce5a6a80c4e6", - "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "017a6896b2b0e534c1c80f13eca4a3a570560800a117ea2d6b4ae0e6d665a969", - "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "ac712a5b5cf3cd2eb2ae3825e75a5d84c5a899f86a104195b200711da15e9e53", - "dist/2023-01-25/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "405fd311dec82db95adea38b3ec0e53454aca72bafd58f7960f8be25b50f9bc6", - "dist/2023-01-25/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "0a3c8988561da39a817a3dba8115237f1c4ab6642f1925f52b7398102184ec7a", - "dist/2023-01-25/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "65b8a84d7355f889de036b1ce760068c2b81d73b43e5f7da29f9706ae1806a89", - "dist/2023-01-25/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1c8843868742c36a5e9f6839275b4ad2b8a45f587f18f798448a674e0b0841cd", - "dist/2023-01-25/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "b225da38b37554abb5a7f098be013b2e5971f9f34c634661d3244dad3ef1315f", - "dist/2023-01-25/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "78018c4b996f7fd8bcaaf6073c84a3180250840263b54cc68ff6d195855b0727", - "dist/2023-01-25/rust-std-beta-sparcv9-sun-solaris.tar.gz": "468853e0d54a486aa0a25dd9fd2ab47c08e48c6aa47838c350c108738d7ca812", - "dist/2023-01-25/rust-std-beta-sparcv9-sun-solaris.tar.xz": "c59fec4162cbd9204d73f7aada19aa459e23f3ed73584203d83d52439a982382", - "dist/2023-01-25/rust-std-beta-thumbv6m-none-eabi.tar.gz": "326a3fe4191366ad170f44bfe726d80954024b1a3c7560d75da77bd16b44cafb", - "dist/2023-01-25/rust-std-beta-thumbv6m-none-eabi.tar.xz": "9c59dca2473fc377b65ce74cda0a3a064cf9fe07b1fb1eca0a4641b6de397d0a", - "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ba2a8bd5d55ee9eefb6f5a5bae987822bf763783ac0374b97c823cfbcced622f", - "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabi.tar.xz": "e8b7df90ffd190d0122d20d4c070f42273bab2da67745f831934fbc09730f34f", - "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "183f0945d1df7a68c45bed842991486ffee21a03313e60e89746ac4122ca348e", - "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "039816d5dc555e28fe45183a09a77a6357ce571111041740d0f95e89489b7cf6", - "dist/2023-01-25/rust-std-beta-thumbv7m-none-eabi.tar.gz": "22c48ee80a14149c2635eb344f74ec5765bcc5b7eb0fa1c7ad55b25c016c0934", - "dist/2023-01-25/rust-std-beta-thumbv7m-none-eabi.tar.xz": "a690f9227a3587f5dc143ab86a1ea7c83777a36b1ff18e877801c73745ff80cf", - "dist/2023-01-25/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "16978fed1307ce642c4c9b0acfb09d9dc532b64a72d25e2d1f3ab3afbcb673b9", - "dist/2023-01-25/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "c1cb59f61a45cb2a842d235762d244a4f4b2f078bc9cd1fe6ef5c632c665573d", - "dist/2023-01-25/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "7d005cc7f199344bf7ecbcb5d3a4acc8ef42cb61d18fa091fe001872a69ab4bf", - "dist/2023-01-25/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "cb567b761f1d78188538e1a5cf4f01aadd641dfec3e8c1a3e2ff2d5e7b930070", - "dist/2023-01-25/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "c7c83022f3772e1f7af9e8883a1082695f17956ad4b2d4b8fafeb2a8b9ec6ee7", - "dist/2023-01-25/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "392e9bdc0d84e9b9ab83f7118abd07ca39df9fb5a8482f6c9a1bb8969db2c1b5", - "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "97f59b364d4a3491f612217f455b1e7285691e12e73e42d4e7a074c301a973f6", - "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "4935afc5e64589ca8f06d3b8bda2ccb89901a60334b50c45be0b760d6f9f58a8", - "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "eb165b5f5924a077c563d7e8e2eef96eff9398432748070b87f4baf0d04388a3", - "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "9c2bf943142fb554fe2332cd7d12ebd568b8b59e06df73e45ad35da27400757e", - "dist/2023-01-25/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "bbd4bb99dbf9b8a178ae767962877bbe8dbd73175e68db654d7eb208c0f10cff", - "dist/2023-01-25/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "265ef776729a591e3867947eb23384aeaf02887a2f03f893bb21489bac1aff88", - "dist/2023-01-25/rust-std-beta-wasm32-unknown-unknown.tar.gz": "177edb18d11154664c510f27fc02b566c40320b5604587975b0897a70647be3d", - "dist/2023-01-25/rust-std-beta-wasm32-unknown-unknown.tar.xz": "7105e29d9a6540ec629a8844407b84624efed5e2a2642a5fc18fa8d73ad5356e", - "dist/2023-01-25/rust-std-beta-wasm32-wasi.tar.gz": "d13a3c25523c269b2515d254558af46bb35fe24d796bdd00aafcc84c63f3ac69", - "dist/2023-01-25/rust-std-beta-wasm32-wasi.tar.xz": "97ee2ec6214ffc91e46e4e590acc8dc4e69a7a935a64a0e2af31940d745e2ac1", - "dist/2023-01-25/rust-std-beta-x86_64-apple-darwin.tar.gz": "d184abb149484d78b713cd1d0f94db958dc4ac182eed453178f669c44856c823", - "dist/2023-01-25/rust-std-beta-x86_64-apple-darwin.tar.xz": "e3c448e63d87842f42f99390d7d0ed18c13e03a226967e8f2e9ef8c764d10318", - "dist/2023-01-25/rust-std-beta-x86_64-apple-ios.tar.gz": "04c884f5f4c4a6d1dfb0941b62e16ec5516d42e6ecdb7b3b86f23994b8c7b295", - "dist/2023-01-25/rust-std-beta-x86_64-apple-ios.tar.xz": "6a3c0e72376a2f1654e7ac08dc5e38794a91b432450c7bf978be97ed10f1fa61", - "dist/2023-01-25/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "fc41a378f93c5bf1280c52d21f495924c2e76925f609356b8d27e43d0650d2ab", - "dist/2023-01-25/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "ab6bd497938262cae110bf9f39cc94f5ef1ba831db19e63b4d60c8fef7f8dc90", - "dist/2023-01-25/rust-std-beta-x86_64-linux-android.tar.gz": "d990e089f838d0158fa2ba3ea08153edb48f4346e682f0fdcdfed1b37a186b2d", - "dist/2023-01-25/rust-std-beta-x86_64-linux-android.tar.xz": "0b6e71cdcef8c32e649dc209dbe9bc30a0864aba4fc85d0d615ff5c405204f6b", - "dist/2023-01-25/rust-std-beta-x86_64-pc-solaris.tar.gz": "3cc30012778b45a27dc6c92f5cb0955461dbd1aba130c191c20a510d29bf2c00", - "dist/2023-01-25/rust-std-beta-x86_64-pc-solaris.tar.xz": "0e3f033b01d1223d9f55c86497c9625c4de36953b6c269ca622c96b2fce09afe", - "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "18a61cd3593bc67eeb93b615c4585e18495128cd4f50933776705c6ff5cf1616", - "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "8bf3998dfd69a17354dd79dea20220f405a2a116842d3813fe033cfa5a6aafdb", - "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "76137f8246ad53adaf26d739c91dd3bc5820697a0c1d2af0937328bb5e6536b9", - "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "2febd8119b376da8f2b1baf3ca63b97d11a17e1a766986ff1d6dffc522cb0081", - "dist/2023-01-25/rust-std-beta-x86_64-sun-solaris.tar.gz": "b5769729f089ea5cd5fb5ba1995a0e18dcef21425b69b7e952d42c5bdf0253c2", - "dist/2023-01-25/rust-std-beta-x86_64-sun-solaris.tar.xz": "a8593120f87887738390e0ec9ff1d72a743a77dc17a33276e7bec7b04f45442e", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "269fec46599b8839f3a81c6cc85fbca7a7e86cb661e5cbcbffb853ba674ae1cb", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "20c2d1d3e64f56f00c237ae261d5880a7fd7c6f1e2360dc7fa0039b3ea932c66", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "d64735ce43c75d7c741f9cb7754812f09e21706be8bd0931d72b09916d312844", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "f501f199bfe1120901e919a14684e57f0723b59ffb5cad79f501834a63df5570", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-illumos.tar.gz": "a80058880e7441e2cd6bb77a7a284902d15dc21d8f0b37f2af3b3da31f07f9f4", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-illumos.tar.xz": "17d07564595b2dbc9eecc8271d3332bef81c7a57138559740c606d2181777f89", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "0e4c01e6438fc005ba7177d33cc0dba8646eb51a47da06b079ef9fc2e264f052", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "1f95934a853b0ce1f4bc50ac86b1ae74a34acbae8a64903faf6f7ba63e49051b", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "431fa66d45ff345f1fb2e279eb52ab24757ed3971f049f9a04a63b228a417f59", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "6901b028b8df3d09e994387a810d3a74b873d2ff5fcf93c1d49bf7c3521a506b", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "a22d8f960e3d15886f893dd4e137becf9c84b1bb2ce500d574e5cc85f43b2b64", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1fa467a1334a1cea4af8b27f7fc186eabf3a8f26091ae29b501bec6b2564b98e", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "50f2c04d4ee499959f52546af600c40b16a5627bb9adddeab819519231cf1efe", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "69084f5bf6e22d6ba232d2040bfee15b00418ab20980c716602a19134ee54bcd", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-none.tar.gz": "5a8b98fce343e17fdfd2f3f9b4f810097cdf12430e02d65b3d1042e273f1ddae", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-none.tar.xz": "d5db956978faa532d822609d475599c12507e5b67ac73b9a9194afb7449b9b7d", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-redox.tar.gz": "3c4f69556a6ed2c64fd6274bfa17ff489b5e0c9f1f8d6884fe31c28c39e15d89", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-redox.tar.xz": "feb6456b55a38b83755b281e039941d97659947b289ac2750fd3b3588cf43fd3", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-uefi.tar.gz": "81e795c668369a3947d4d69aeb4f823c8446b09ae18c6fdc800d54aae514f27e", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-uefi.tar.xz": "5c51b99639e5f67e01fe37a868dae17da4ff11d755434b189cc4ae81453826ac", - "dist/2023-01-25/rustc-beta-aarch64-apple-darwin.tar.gz": "9d6277d58b9a679d47eb80d1132d590102f632d5fdb85ba54ef653b2e602c6d3", - "dist/2023-01-25/rustc-beta-aarch64-apple-darwin.tar.xz": "6a49fa544dd3bc4d657ae064863b760935977674e6c837f6a7f84dc1c9dbe95a", - "dist/2023-01-25/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "0536b525d92007041a4d5f4b57601bcc17e1257f44eddd1e4630fbda8b5ea2e8", - "dist/2023-01-25/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "35621c50a8e1ce5591dfdf95b4f5e17e60478309348e67f6e3bf767b57c494ba", - "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "feb0c0534f2f78500a25906fb6f0bd5772574fbfbd23b6abea807f074905905a", - "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "fb269a472ef44aad092259352bb55b24dafc56459eacb7300fd7db0bbc5a96c1", - "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "98514e08e1a21f94028df39496e802f5b6379414dad4e7069253cd8b3f961c43", - "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "b01b5ef23232834174ea31bbf402fd4652769a7fac5b522ac28e53c469389b60", - "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "d638873a2fe3bb666174b4270a44da25a9f7f05f0a2544598556485661b51d66", - "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "7bd32b738a280b6d42fb925b5c7cd8b4ca660285ae77cf27b0ed6eafb0b0237c", - "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "8ed861c6ccc085030bb0947119746df3c83b9971e7b7c0ca43a8133700f985bc", - "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "f4ffb8ec45475b96815eccb657d9a5f443e8067a2f7b50a18eaf80c8a9cd1944", - "dist/2023-01-25/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "e6a809e4e255e265aa54ac730655569e93b0227037e5eebe2995e6ed13c4a2fd", - "dist/2023-01-25/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "0849a22e9d82c3cacfb39c5067106767bc40380e231842e968770b7d79dc9376", - "dist/2023-01-25/rustc-beta-i686-pc-windows-gnu.tar.gz": "348a94bb0048a2de0764ea5ebc83a6578d1f63f4edf8d6627cd346345cb3beda", - "dist/2023-01-25/rustc-beta-i686-pc-windows-gnu.tar.xz": "02885355eefef4a901522a441c376a59521ff91889dd6e2438cfe5869360ad7f", - "dist/2023-01-25/rustc-beta-i686-pc-windows-msvc.tar.gz": "56d6b9b2d0e8eb13a568b60f2b5284cbdb3efcbc921d6c318408c58d12c6ee11", - "dist/2023-01-25/rustc-beta-i686-pc-windows-msvc.tar.xz": "bcf405c76b2aebb76ca70595ddbe5de1faf8c34320b08cd4839db7f46dc9dc7c", - "dist/2023-01-25/rustc-beta-i686-unknown-linux-gnu.tar.gz": "6b5c11f41bdb8a7b596ac92bfe18e7a2410a7fc77fe7ca7036e72c563b9e41c0", - "dist/2023-01-25/rustc-beta-i686-unknown-linux-gnu.tar.xz": "7291ffdbce495b5d0ca017730495300a72d3341170d099b3c8abda5cb9ed190c", - "dist/2023-01-25/rustc-beta-mips-unknown-linux-gnu.tar.gz": "6005076b8cd38020a02cd2720e8c67491d31f50465d62d9f5148d93feb4eb198", - "dist/2023-01-25/rustc-beta-mips-unknown-linux-gnu.tar.xz": "1b421c2addb488faefec78cdcbbaf03a9c45640f4ba6740bbb1afbece3e30ba0", - "dist/2023-01-25/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "2d1f7463d3922238c189c5f669b8f4e80f85f389f5edca000b63ebf041fb4222", - "dist/2023-01-25/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "29dcad8e598e6b79730a53146d3d8ceb5acd0029a83216060ece931d149e9a97", - "dist/2023-01-25/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "c3e1527a463155bc9ed2c3eb65217c72fd067bbd316432a16a2777a444e7eb9a", - "dist/2023-01-25/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "8a031c5830bb8168c1e20426082c0783fa52310b22a28c5fbb5b1214adcf3bd5", - "dist/2023-01-25/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "5c1af72641cb7bf514f936def835ebccfa908434f9e26e6d3cf65756d68fe24d", - "dist/2023-01-25/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "40a95925bb98eadd7b49be71dd9fa76abf09fc16bd2d6707e3206cf7e7f9b9ce", - "dist/2023-01-25/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "2dfea875b3b5f3405f9df83fd5a5144b8fc93a90ba17a3ffcb437c934a9772e8", - "dist/2023-01-25/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "2c23590890472f2ed15df449a33188bbc7d3dc8755e8929861ccdfeb24ee0909", - "dist/2023-01-25/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "0b31cad32717c5c7a75069bfaa32fab82d0eb75190b0d34d2e09c221def5f7a5", - "dist/2023-01-25/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "939feb641d84aa98e46934c3896adee94169d8e5d8d2d97065e904aa1eac16ad", - "dist/2023-01-25/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "d031874dccc1fc029196bc49f7713805226be2ac03a17fc38dc2f40c7f807093", - "dist/2023-01-25/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "8b6f367822b14dfd341d711c4736e00ac1fcc914a3c5214209742f2543bba880", - "dist/2023-01-25/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "6fb98f6c504ff7278af6f840e39d1236b7209a35a3f5dc78d281c59a2264b525", - "dist/2023-01-25/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1e5a16e7c67bad200e3f051aa959cd9123ad26e15443128ee9ce28151b28e7ba", - "dist/2023-01-25/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "c8bbed9a7319e601e9e53461665201f89aceca9bc72dcdd1e3206110d535c6c4", - "dist/2023-01-25/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "05af8b1637b522af7ac981d133eaf88c157a7d4ed414ce53c13bbca0667510dd", - "dist/2023-01-25/rustc-beta-x86_64-apple-darwin.tar.gz": "ead6472d2644ffeb7f27252e0445aa27b9cb028dc982da011069975767711249", - "dist/2023-01-25/rustc-beta-x86_64-apple-darwin.tar.xz": "3777d00c129c51b8980afc2ba1b1605f58490ec4d5203609d260e05ae5801182", - "dist/2023-01-25/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "5871e7fa9b9af9af9ccc405866774db110dc5ba8b66649c87f546139c383cea1", - "dist/2023-01-25/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "9804f9a57acfa97db3a33fa7f77f5a8ced7d6b9e5013e61aa76287dfe45d9223", - "dist/2023-01-25/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "3a7387c88e4a17e331d8f8800e6be0cf113242edb2b760fcff0dcd2ff97c1ca8", - "dist/2023-01-25/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "12becb176b75b9274a44ccb22a4859fb8cb52df2cf954011c7294d22dc2e8721", - "dist/2023-01-25/rustc-beta-x86_64-unknown-freebsd.tar.gz": "262df9ec15e8b14d1a2959f9d386717147af17612ae92762916e9e195ac83c7f", - "dist/2023-01-25/rustc-beta-x86_64-unknown-freebsd.tar.xz": "2647f9420cc4b2a2a94b32ef6c7d88285bb50c3b04bbd29bdc11f6e5fb8f9c4f", - "dist/2023-01-25/rustc-beta-x86_64-unknown-illumos.tar.gz": "82875b6f60bbdea438f0da1a162c30d236fdd32124296a83510954f89dfbb20d", - "dist/2023-01-25/rustc-beta-x86_64-unknown-illumos.tar.xz": "19bd296d5c116bdb620e50b6fba3c7d5a5e978f26a8f1be1afec1c6854408d2c", - "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "45b8d74f203b66d25a15e59db755918d0954a3338f08236664007de2478e2438", - "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "c047becdba71a802c1d06b31e5c3dce8efb11a9daa299e1cd03a0f9f6b48cbf9", - "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "a649445f1676acafc59b4808211aa669c9fb8093cabb7007432d0ae2f6e21239", - "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b6ed06a8df0de6b64099fba4d1ca9478e0802dfc086308f425692ee40faa8d2a", - "dist/2023-01-25/rustc-beta-x86_64-unknown-netbsd.tar.gz": "d939bd071f42aa7657297110be68dd9d2aad840272bf881a1fdc82053914f970", - "dist/2023-01-25/rustc-beta-x86_64-unknown-netbsd.tar.xz": "5671084575291d8c4ef2ed0930b22815d6810e2378fb98ca5a0738faa76b525b", - "dist/2023-01-30/rustc-nightly-aarch64-apple-darwin.tar.gz": "f634a282a8388aff57d988616f17f2c511253a02d45193b03fa87167448a8cd9", - "dist/2023-01-30/rustc-nightly-aarch64-apple-darwin.tar.xz": "4fd6a4ec8665ba71ccf3ac7d08f9010b4e130ce496bc62548d36170786f213ab", - "dist/2023-01-30/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "5b7fc325745b2f1e22b1a58ead8163314c3ec06f4a30483bf7ddfb57f811a2d4", - "dist/2023-01-30/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "4aa8d587ebd53bbd11c33f263991328576977d801d5b6eccf56147301ea0f52e", - "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "7838bf7da92539b0329be0b9b80f0738df3617e982f539326a6a99892eb905f1", - "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "636af094f94de9baa3edd5f9e1b7655e0bb7f6f23d24d6f389a3abeab7360e00", - "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "51b8a8a06244ee37d2c37e84154ff87132b4f90a1e62a8c9454ed5ea5c296c1f", - "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "cc18ce5f4f461a830c725ca8ddccda17bd726374198c487810eab8d36a8f7c98", - "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "e2d7b96bf5e2feb47019c63067dbb1627bf26ac4e730774d29ea9f6967edae3a", - "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "0483f07f1a53949c2f04e2766f53fe9138ce126059f650ac61215e6a84c5fd57", - "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "d3ad417041c432438f1ed56a2324ab412dca7631a74da03e0bc72cd28e69f197", - "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "f029fafa0635efec9065d76780f003e2c4220c7b6ea4b426ebcb57d943403998", - "dist/2023-01-30/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "dd2ee13ccea00c23ca2f90872c7c31a3a1ef008962db9cf8066acc130bca778f", - "dist/2023-01-30/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "dc23fa4c0268a7227e0f9e4941376ffc4c64c0614622f442da10dbb75e014dd4", - "dist/2023-01-30/rustc-nightly-i686-pc-windows-gnu.tar.gz": "d4b02e59373fe60ba06e979f784bf1b8c94ca4a5ee471ed83814623db9e14af6", - "dist/2023-01-30/rustc-nightly-i686-pc-windows-gnu.tar.xz": "5355e1bfdddd2a56dd0c882fc492e4d571e5b29636d381e848102e996ca9b680", - "dist/2023-01-30/rustc-nightly-i686-pc-windows-msvc.tar.gz": "02a43fb72394837461770c1b472afb534ac03bac9cf23bfdbba8227cf879dabe", - "dist/2023-01-30/rustc-nightly-i686-pc-windows-msvc.tar.xz": "78cbe74bd0f7029b01e3aeb451ea6bbc1656db1fb4a80caac4cc27b6e0144b79", - "dist/2023-01-30/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "7fa9a3e3d70a6c15bfd00a0b5a83d73f4e952862b8ef1d6837d3598c4cee8752", - "dist/2023-01-30/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "76b3abe5c532785ab80804461204280e6d853773c62956f283f5dc88130e310c", - "dist/2023-01-30/rustc-nightly-mips-unknown-linux-gnu.tar.gz": "2aa78ea99fceb90e568f6c46881623f5088afeaf47ba204abf2ef755397e84eb", - "dist/2023-01-30/rustc-nightly-mips-unknown-linux-gnu.tar.xz": "6abe1f28662aca904b1fd91e46e0441ba7b4f66f1e7757cab93a0d73012b36fc", - "dist/2023-01-30/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "3afadbbe1b073ee2a81609c87c3d88a5d7344765b970b8c48dcdfe539c5ba540", - "dist/2023-01-30/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "f1eb22696c376dfea266090320e7a941986f8de2176b6ceb6dc0f0452994ae4a", - "dist/2023-01-30/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "c7f548350e118d4281a8a6ac8044c19eb1583683490b0ea6fb9f5f27f5e3873a", - "dist/2023-01-30/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "aad40926a20ac8bda9e534d63e180adfa355e9df22a1068310cf9ae667ffd0ad", - "dist/2023-01-30/rustc-nightly-mipsel-unknown-linux-gnu.tar.gz": "4778f49dceea661baaf641531946dda47d8ddb7f801cc63afbec37a86d45a0f4", - "dist/2023-01-30/rustc-nightly-mipsel-unknown-linux-gnu.tar.xz": "1ba09bcefaf5ed5a3029230ebc3e9cad33626b38553451b952ef215c68a98e34", - "dist/2023-01-30/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "6efe1f619ad49c94b3e6fef2a51893cec88ecacf31d963576e6343e8a050d20d", - "dist/2023-01-30/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "971fdc824861c98bf223fb2c733e780cf87c90f3a5646561f4e35fa8cd068c7c", - "dist/2023-01-30/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "10741ef62e00541a85747db16f830c71ffa1dce036a95bc43df433e450f96602", - "dist/2023-01-30/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "b8bc80ee97c54e428c51f56e30cdd610fb07f41bead0409b089fe56237bb0421", - "dist/2023-01-30/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "f8f52abf57943895d34ffe2157f863bbdabaf804969baa2624e38a13648d43de", - "dist/2023-01-30/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "7dfb9af100df05b558c873b5440c532d28de44fbf8c7d933c29481eef6693539", - "dist/2023-01-30/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "9454d78432ce8ad61f8cfbe448654d8acddda9c596c36c7863631c638aba949f", - "dist/2023-01-30/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "c69f1b0062aaf566d6610e6b19335ed002a281aa65b34c1be001a875b85f76d2", - "dist/2023-01-30/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "92184254f00348bfaa7f40f8a07b585eeb6dabc02e4dff3351cb395b354a930a", - "dist/2023-01-30/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "b41eff99cf9b9851ffbf496ba6dc892d5dfd124da68c91db66d6fb77b19370d4", - "dist/2023-01-30/rustc-nightly-x86_64-apple-darwin.tar.gz": "8d901d7c2ed293a9e2d2fb8849edee50e6f6e3c5a049fa91cfb13f8f16571b7e", - "dist/2023-01-30/rustc-nightly-x86_64-apple-darwin.tar.xz": "d472dc97f3242d243f584efe113f23e62ac1f53677fb3b3cd1749adb65a6635c", - "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "9259adfb75f90cd43c99f253aaf4b242afe941c4075eabc6bce824c3337b4d2e", - "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "e42b3e9a462004296e53ed3e71403caff98b3718ff15508d913e0a25ad02ea3d", - "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "82f615142be1fed6ffd5c9a6f2d1d3fb73ebf32801348cf6279991c0a76b771c", - "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "2a4e2aad343062379334ee1a73b657656e0c03f0490c901806c864ea8a38ebe1", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "2a8fa3a6a104bd35de9a83d98786e7acb7614e0b830336adda30e8d1f1cade69", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "37327a8b756918c25cb799f2e5742a07145e4c1e424442a5d975e99aff1f303d", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-illumos.tar.gz": "8be0295e8b89b6e8f465b0825b0625232c7624cb897efe3e0bf4da222799349c", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-illumos.tar.xz": "8e515082490a64d83771131f4fa5fba8b021d205b56149459e2f2da7584407e3", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "c105e3dabdc7bebebadc6ffa5b6f3f962057948cdac6647cd5adf16d66982701", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "09b82ca24ff847e000aed1b2eaca74cdf0f6e533bd6655eaa302281eb7037163", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "e77d81b158b53a94065cd90f68e26dd12d156084b02c53c51172e02c4db58c1c", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "613c7eab1b998aec0673e1781e3ed78c4d038b449d879c11254b1b6d4345e34c", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "ac8c53be048049118af9fd9d356dcc69ddfaafcd52020ea93703c94d6167b367", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "28b1c8adfffa7863bcd8a46ef407044d06fc16b29f7b6f42072fcbfbdc779e79", - "dist/2023-01-30/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "f7e585d9016a012e2cde4d7e0899e52e1c410c53ed9caf6db22d13f6791ffb0f", - "dist/2023-01-30/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "bdea28e1700f34dc0a6e57db5f73caf6c8d1671a8356cc51096f8155f58690c8", - "dist/2023-01-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "e9988193283871e678a0d0e08cfb5bdab37d43cb0bec0e5f63a12a38c164936b", - "dist/2023-01-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "30d1bad2b730589f9d75ca3e2d410d0f9c90707526ed6a66edac92a19eb3716c", - "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "7c6c93fa25193360e28a90269439b28465b6693b6ce68ff2eb1c4209c36a9d60", - "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "4c8331d14ab428b922135690b433f97acd37291e1801635252ab5da849d42180", - "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "0fb5372bf4cc0b6388194021dc7b6a539bd413e89058c05cdc42c1dfe8d92edc", - "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "0e2452ff037698781157c30c5fd67f552e897feb1d86b7b074c195c70a6a1a3a", - "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "6c079c2dde918cf2d9f029dfb3a2a9bebba2504dfe97c5fdc0ef79022415b9f0", - "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "5ab6fa16d7aaca7e6e36caea8e11b916c089dccb511f79b7f69bba667edabc50", - "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "7b919c9132269fcde24559af58d3d2fee56d93308d731d891f89dcee193bbbdb", - "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "53d7c7d03b64526e013c11c49519a63f51562f9682039479c377c92529e5e026", - "dist/2023-01-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "c19265cc3a85cd296a85b450e2f4e4b5f3646aa70d6c70dfdfe9ef222fd72136", - "dist/2023-01-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "66159d87fd85a4534104da3f7f5c0a14403960ff2c836eb72e35bed6a1ebde32", - "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "be84f8558d15dcc802f399f44f0de58e93b28e99cf62e38c0d6e6078a8d73102", - "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "b4e8f18335aa3cba092df29c3aadef79c0b88e00f563604467cb2485e10cced6", - "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "43ce7581f50e05c775b39a6a6d297d6e8c56a40f5a5817ae4d996d319fbe96c1", - "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "2ca2b20996f1a4cbdb619393a3f544ada208caaf381748ee997a70139e52a591", - "dist/2023-01-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "229fb281ec100e68445b5a402a3d39a0947475054c4f043d55ab2e33bd3d2a57", - "dist/2023-01-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "65326115afcf1c8e07cfcb9ed294a1e5a136b998557cd60b4cb976520f84cfe1", - "dist/2023-01-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "337bdf61237c8e47909c3f14b5c8fdf3b8b14f2b265e6da45cd6b4d8180d0afd", - "dist/2023-01-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "d683349af8320d6bc9f16021fc8937920d70e99cf668ce64cad962705dd20ea5", - "dist/2023-01-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "08a1ae9e61ef097c5d5ce83e5d2bdda62e72d07b4dd21aad286413c619fefa1a", - "dist/2023-01-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "cc3f1f86997c5ccf5607c8f873c916d1158da76ff971d75e36ed8e3a87c86924", - "dist/2023-01-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "f4b7084fc67cf17b3cf1d36136aa03aa5b6af188d311684b15395f05104181f6", - "dist/2023-01-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "2ab645d5117606f2c7e8decbeae1d8855ec7ba53051144ba4783efee2c58d91d", - "dist/2023-01-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "cfa8baa60cc59ac2750f799d33b06eb399d330f318783907717a9e360fd7d85f", - "dist/2023-01-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "bf24570425c064aaef31788bbabd6c4938c9323eca2dedf2ac9084d125623544", - "dist/2023-01-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "f5437d81735fa67ef24c7b561d1c720395f5d8d4ddcfd88364717a7ed9b96a7d", - "dist/2023-01-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "8e19c3c95d6445e1ef9b1735191f0d0bc33802bcfa138a9d676d9b266adab17c", - "dist/2023-01-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7fd91c2ef7e26c08854c91969d167d1c97538d7678c6ed7914eb0f67290d8d5d", - "dist/2023-01-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "9e8ada358580b396054278972d532ce2044550071036e9da2eab598e2953a03a", - "dist/2023-01-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "eec8b1c24ccaea22eed7708e61bd32bac0850d0dff2b06f1a15a95ab86385363", - "dist/2023-01-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "215f1f3bdd8f347af5969c66ff7f7cbf39753ae483e75e689ac581f9d35a64df", - "dist/2023-01-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "39460814c429b6a57ce72fafa583d04190053f2c2ce995c8bcb0799ecb7f8bd5", - "dist/2023-01-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "6bd08db8702f2fcd9f4cd19a1d977962c84856f748552a96b564e5a77cf2fdfc", - "dist/2023-01-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "81d6335fa1265cdf99682503cfb236b914fa17d45f967e456ddbeb12bae2dcbf", - "dist/2023-01-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "d36b7517efac2c4a34a1055411f779c386c7a566e4eec408dbc8a319f67f5451", - "dist/2023-01-30/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "1a34ec058cb45189c4062ad2a00ab33387a54716f75005d9959cf0691d06ae50", - "dist/2023-01-30/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "a2fdcb7cc9fe7819699f511d52da0e8ed4e55ba42c63e7b1d61512e4e14e5c29", - "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "95e3f080394d2e4f9916f17c9cf5137d032da847d9ac1c04519b31177fb1618e", - "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "c306895982f92c24559b18f8ff9e011e8722c3310e5f70010fd04b0d044c49bb", - "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "36331cd76f8e918b73ebf6d9095efd0a07cc9f084f194f74c881c14fbc6e8a77", - "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "2e7caa7209e52a9df17254b17f1930afd5ae973826ce3293f29b8b878aa13042", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "dec92f2c27f785f8ae0db18c2e8a9db87e1ae8addb4302f5cbe9f745cd92c4f2", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "a8fef2e56d9d2be9072c17d75e7ac695eb8fc266fc35e1055fbb25757e6db29d", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "9b5f93f00f61def125436332e4b709bdfe74c441995bae49c0d482f24bd9f8f1", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "4f82313dce2e1315bd0d3ebf95f33bbdf7275c59205b0910bbc92d41c47c7c22", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "69efa04956d9bcf177a3bd9ba9541fa681b39416a1b7dd2b18415b72311897b9", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "0c3c33d744ec05e96298d0bdb9890654ab9ce3e9013b9af14c78683560456820", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "cba8b1f086c544d79aa09ac954374f44d5e7d38ad9bbc2f9e84723d0088592e5", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "ce73d1d03b62931d6eb9508b701e9dacc08b98b484af3daa79ae600c4883a9f4", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "87e1018a3ee4f781b3c1b471fcdf80ebd70096ed58b29db00ad97573626294f4", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "c6896ee319403ebb5c909b13feabc7411e3aa80523ef1bc84c8aae181514c923" + "dist/2023-03-07/cargo-beta-aarch64-apple-darwin.tar.gz": "ec2466b2212a7453ae902b85f7b1879fa9d37275f21972aef488e8b4ca04e195", + "dist/2023-03-07/cargo-beta-aarch64-apple-darwin.tar.xz": "5eaa63f70f842836dc847059ec188d5c1dbcdaf77116dc08ba6421eb09706c12", + "dist/2023-03-07/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "5514aa4051d8c6ff9b7e334a4cbc8b2ad5ad8db0b9853a693ae998888df0070d", + "dist/2023-03-07/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "47b4cdc96afb1796e8ddbf4fed4868d08bfc8fe90c5f517f7c4d8539d89ca827", + "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "514ed7e95642daaff551b31af9f6b8e1afd301d4a3197574c4296dd938f7f98d", + "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "0a3f61fc865330e5a9e1f37a59226a6660995ccae8610e742c2ea42a7b8f9b9f", + "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "838c7a9cfdf76e3e2a0e9c2ad37124eb029ea2f0e015640c7c9ca5f45fe1c260", + "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "1ee5a28da6b8f7fc5f98b8214ed2dda28769dc345c9ffc8046ef644f69fd0382", + "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "3ac81e710ff821e206148d998654044d0b3092d929da3a1d3a5ffa2ada00d922", + "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "64891e59a7e8c94011f98849d37a056535966966f753b923ffcf8ceccacfaf03", + "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "fcab9d5fddbe72db02964adf9fcc13e5acc67f0f65bcdd3bc325aa9f0c223acd", + "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "2bfaf117eb512e53c4f01765d198b3647fc0058d7f77721b58cfab5e72b1f7ec", + "dist/2023-03-07/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "dd955a4f258603e5cb5c85473fb6bfeace54cbc2345d99dc9d8fa7f984bcd915", + "dist/2023-03-07/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "7b19dbf54ff04009209d505a97bf66327a87ad6ac8a9be4aa26be3d38fec52db", + "dist/2023-03-07/cargo-beta-i686-pc-windows-gnu.tar.gz": "88e8e79c154a34596740b85030c16a27d62defef5db8eefad0b3d4397e7222af", + "dist/2023-03-07/cargo-beta-i686-pc-windows-gnu.tar.xz": "a996fac21b8198632a3bb3746549f6a36bd7c2b12d9820b7af64a5ffe8074df5", + "dist/2023-03-07/cargo-beta-i686-pc-windows-msvc.tar.gz": "3b8834bf152ecf2bda797475d7d556746e2a1374c61e4ab2ff81b41bbff3a87f", + "dist/2023-03-07/cargo-beta-i686-pc-windows-msvc.tar.xz": "2fee05bf93a16004f4f8fde437918a44874a9495c1e45d954a1098c104249bd2", + "dist/2023-03-07/cargo-beta-i686-unknown-linux-gnu.tar.gz": "544ce4096e455c5259c4577feddaf5a6ec34e6a8bec2710e74f8910f60c1da1a", + "dist/2023-03-07/cargo-beta-i686-unknown-linux-gnu.tar.xz": "2f39706fa21cb08d8bfe6a32a5a3314742ddf040bb42e844d5b3f8d0d29fd39f", + "dist/2023-03-07/cargo-beta-mips-unknown-linux-gnu.tar.gz": "7f60d7a0d60e06fb4530291f1e64956cfc7c92bd034b63d1ebdedbeb9f7bca17", + "dist/2023-03-07/cargo-beta-mips-unknown-linux-gnu.tar.xz": "3c6d8de9f254edd01461235f14e89c7b863da84f338e3a842921dc092db4d82a", + "dist/2023-03-07/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "2c0ef292ecd4bf27e74323ae5fa7bd6c6395d70f4adc4e6d4228c266fb87be7d", + "dist/2023-03-07/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "1886d8e978dddefff73f758e7c1d28964209dc986195cd39bd8d3d34197cde52", + "dist/2023-03-07/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "125a9a8a6d57f1694ed5bef51d9d351da3bbf0ff1ac631641cc5046098385536", + "dist/2023-03-07/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "851654268ac5ce9d1f3dae9228464bef01771244945653ff7e9f8d7a52761813", + "dist/2023-03-07/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "46a3bd35af46f6b59b610bbc596233bb428c2b8387f95d3e308565d57e6ca276", + "dist/2023-03-07/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "d941bb502be268962400e78005b30ac4a5975ab012e2cb7fb631b002a7e116ec", + "dist/2023-03-07/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "3853bfc5c0734f3f92e0d7cd07583729d3e67f7ec3b496b5349ac690ee3632e5", + "dist/2023-03-07/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "17a0c76f33244ca66c942cd6054e343a395d27437d69f166471f0aee8c404a55", + "dist/2023-03-07/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "b37f9c476ae9fe802bdb0fc449657c90a567033f4df382befeee1517f53db05a", + "dist/2023-03-07/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "b315d765b176f90a5c74c102687ea8b54ea94d5a772ad03741aa3297a5466562", + "dist/2023-03-07/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "e84ef7a7b4fb7b504e6a0ae335432430ad9f4db356650c738e0db676ce672321", + "dist/2023-03-07/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "3b830e1077a195e2048b621a1ace2c0470135ae5821f83113a16bdd449dc9828", + "dist/2023-03-07/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "db373e61134b7f9340b5d8dfa24fb989e3acadb90b4d27008c08715720cfeba5", + "dist/2023-03-07/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bb7d046253f1fcf98f8ef9b33820793579a09d201ae1bb5616302bcf7103453f", + "dist/2023-03-07/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "495c5d11852010647d15d54352052ca932034d77f3ac3bd9bf605d52c37fb47a", + "dist/2023-03-07/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "002d9a037a9de13d0e99f695bbb8f9177e14df2e6309917a7d728023dcaa1640", + "dist/2023-03-07/cargo-beta-x86_64-apple-darwin.tar.gz": "9c93e76966a317d2dbb673345c33269b67d6db101114275424a50f5e4c3b7a89", + "dist/2023-03-07/cargo-beta-x86_64-apple-darwin.tar.xz": "0ac70e1699e2684fcaff30d4330d04795f3f9579226dc1dd0ecefaed9efa24de", + "dist/2023-03-07/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "8ad0af38dac9c0a49d73691d7f62487c8c72a378ff4fbb7f380fd106600ce836", + "dist/2023-03-07/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "e1c263909d66c14d5b835d2d8ba9df9d1f54750a85b79c4163483126594f71fc", + "dist/2023-03-07/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "684b44e6cb7b2ea6feb8a5f768f138b7c3c3819ba5f146461ffa860e4ba2ee0d", + "dist/2023-03-07/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "194037a4e7a035becdf8540532625e7a3d2e5e9a75c093713467d16f2c630fda", + "dist/2023-03-07/cargo-beta-x86_64-unknown-freebsd.tar.gz": "b19ed2a67bc6d654520c2ceda0d1a8e0128a0d042a72cb6506eaf975c3665bc1", + "dist/2023-03-07/cargo-beta-x86_64-unknown-freebsd.tar.xz": "2773155eb716d1cde85c8ee7fe87f534decf08cb92d4812463a8f5f45b5cf4b9", + "dist/2023-03-07/cargo-beta-x86_64-unknown-illumos.tar.gz": "3d97d07c075c7473645b71391fdecb6b8a43af42f15ccce0bc13146624f3d9e7", + "dist/2023-03-07/cargo-beta-x86_64-unknown-illumos.tar.xz": "6266332b1a18e851cd4cf618c1ba5a8162c06c8ceffa3a6e619cbfaf5c8f2914", + "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "6e0ca0e10d1243e81768f1760f268aa2ce1dcf4f79a718a44e09b92ae5b2c87a", + "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "84aa0a73dd6d3ab9d5efb10e0480dedb864341124c19b35040239af27fcd8651", + "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "6de4590228b94c6c62fec90da7f5579fef16cddd30d4bad29ac39e40081818be", + "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "317b64417648885b08064543e0dea13d1062e682224b3b866c12ac6abeda1648", + "dist/2023-03-07/cargo-beta-x86_64-unknown-netbsd.tar.gz": "aad64656cc4b9915bfe5ac780ac935964a13481a9070ca31f58d5b8c1750e40b", + "dist/2023-03-07/cargo-beta-x86_64-unknown-netbsd.tar.xz": "0ba3f47a551b38c83106003c775539b7384c9bbfa4cae28923e63e28a32227da", + "dist/2023-03-07/rust-std-beta-aarch64-apple-darwin.tar.gz": "b3f00164840826f89eb930445cac0afa2ebda2153195574b91ff4dcd286042c1", + "dist/2023-03-07/rust-std-beta-aarch64-apple-darwin.tar.xz": "c94d3fe8dfaf35f88d557a37e3aa1da8999b5e2e022f85f1bc0ae7ed5218a3ef", + "dist/2023-03-07/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "3f43a002c0c099eedf12c2d2d3e1bee3c8ea345368e89cedd5918705f37086d5", + "dist/2023-03-07/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "891547f5c2d06ef95f272f829438b0d5c9f34d9e1e7d068dbb0a5d31c685658c", + "dist/2023-03-07/rust-std-beta-aarch64-apple-ios.tar.gz": "c1fe0f8fb661dec65dd7a13b038deae93d4b66f0e0988a0a72374e9945915612", + "dist/2023-03-07/rust-std-beta-aarch64-apple-ios.tar.xz": "1f65f0ae9685aaf14805b63111ddae27c8e9b39cc88cb3a5347ad9e93d863581", + "dist/2023-03-07/rust-std-beta-aarch64-linux-android.tar.gz": "9fc988f57fb6a0530a338cd3a0a87925b095e9a2f3887f87231c9414828241c5", + "dist/2023-03-07/rust-std-beta-aarch64-linux-android.tar.xz": "2aab2cc1377391588db019a231d8f989de79342a630625a4e7c2fee560549668", + "dist/2023-03-07/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "4527b7439a0419e96b8c59735fbe98d8628985b63ce64c24749273b625012c39", + "dist/2023-03-07/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "80badae3069223541e3092b07331eab3330bd66a21522037fece15314085c513", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "6f7141d28b549d6cf6f64a5944a4748db730d865a9bb1f3a344cd19cd45269d1", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "87f97fad69b53a36354c17abfa58edbaaf86d1db071a53fa96e9822c4f0a7846", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "8decda618f8cf30f51b8f26861baab0f53824af6cfa965af585f0653771d113a", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "dd140223ec842ebe4c69ec6aa2966b97dacdd9ce112490e310f374134188d0c4", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "4aa6ad6fbfb9bea40c5b4c3fdae8f79feeaeca71f0848c1e9281650d4b5880e5", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "2d62f25f3c16704f2f52b8bf2fb505b5f8e3a3e44ae3971b0a3081fdd5932bc3", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "87982e6e6e3865d520fa35994948c7b82c4fc9f698b4e1316e0ab0bbff3d7455", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "815a45384be320225b438be952d798ddcbfc223d7629ce8e106499f626c170f7", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-none.tar.gz": "041d4a16c7e6ea18f76b119e069630636716c5f7c2f38e0fdfe69062da9cd942", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-none.tar.xz": "227e8434ac0f294bdb102d4aad6c6b1425f148f2bf8eac9473f522e4e8851d15", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-uefi.tar.gz": "a1f6c1268c3e28e78f43f2a922ff2d260466f4e2888555c122fb490ba28d8f53", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-uefi.tar.xz": "68f46477d721677d2faf0091aad1d2f72387bdf1e5590dead06eec51390e9906", + "dist/2023-03-07/rust-std-beta-arm-linux-androideabi.tar.gz": "d1bdca54a9807d058a26f2999fc82ae474e6d5f8cb555196f6583130c81bd6ee", + "dist/2023-03-07/rust-std-beta-arm-linux-androideabi.tar.xz": "8cc49d1e16181848d73d617914d664b45cc42fc8bf80d3bca7ca69fe1a4fe7ee", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "b09c3776268888966d3752dc614e677c821731593ef757ce45fcd6f6b1b28bdf", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "7d43314c408514ece5f3ab6929f906bb224336171c3fe41a5b980afedfbeb172", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "9493fb7c2cf30e0c986babd8ec41e3c626373d4e62f8558dacd01cfb85dec04a", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "9c833f219410f9e6e77451e4af1a355685831dbeaa99006ac814801883a17312", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "8e9c3045dbf1fba7e54b8d34bbc3ed8a95b6c984ebee0123690889455d963f87", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "54f7f9a2baf29a5fbc41b6624a4ae0f056e10f0dbfffffcd08377dc6888ca85f", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "3f214ab1da499c6a64bc5bc54fb9e95becb318b469531e4d9f7b234f5456dcff", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "3e4c0742356393a07cbcc6502e1d1f9a3187921c67d4d554bc3c95bb9e4e226f", + "dist/2023-03-07/rust-std-beta-armebv7r-none-eabi.tar.gz": "25f7466a419353fd7e4c9a3771df8f0a64e689d3c38f18e297a6a2c670174d9b", + "dist/2023-03-07/rust-std-beta-armebv7r-none-eabi.tar.xz": "42c713261708e90fcab6dd2b8d5b2df4387a33c829bc981f502622d5ca352ac4", + "dist/2023-03-07/rust-std-beta-armebv7r-none-eabihf.tar.gz": "31b240296f2e72dbeb3facf395486e8f8ac0b0b5f10a389ed4e6dd803821afac", + "dist/2023-03-07/rust-std-beta-armebv7r-none-eabihf.tar.xz": "c33a7bb47b94f8d5c716e4d6b43bf17395bbe9611762a01a5763dda4e725c64d", + "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "509cdcdc107051d7cbc8f02874445a9cb2f0dcd3190cfabd68615b8883b8f32e", + "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "01fb58ffd2cb6257f25d290cbd25be8bf216c18ccbfd97a42317d9e442008d4c", + "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "19ada8a7b1178056008f3168dd854994d6dc0fd32facebef915891b5a7fe83ae", + "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "5925328b29a9a54536ea7de55442f4bcacce4b2ec01c69e7c8d5e7f109f5dcab", + "dist/2023-03-07/rust-std-beta-armv7-linux-androideabi.tar.gz": "bd569b576ad68f20d0352e5ae9a7ea0008941f879dcf1cd57f14b7eb7fddb95f", + "dist/2023-03-07/rust-std-beta-armv7-linux-androideabi.tar.xz": "c483223f7abed0c145b9c94a6630a1d4caf26720cd451cb4b70971f1f907d6cc", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "84a1ea166b81fe2cc673beac5831ee182a303c5166279af33478a730a1987086", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "fa04a59350792a59c8b62800002f5f6e013710d96e3e9d3a6787b1c3b668569c", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "a605160aeef9a5d60bb83376d816112c621f753e4f16907481aeeea27568da77", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d6f3e091217d657a259f7392acf26aa7cc2a7692028412bb97cd26cb7f31b34a", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "ce179ad977098491c2dd27d57d7dc5a71b9b450b07d36c19e55c0cf9961d3888", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "fdfa1b894ef5d1afe7cf9790de3077632d4fe693464d19ede5d6b377ff09a73d", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "673dae7f6d71cf984b69e0bf22b8f50a8597d5c6304ac0fc613ad5116c4a8fa7", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "9bd8bd07be4488f6828ce4b5456bcfe49bd9ae416cbb859c9b1460334ac9f4fa", + "dist/2023-03-07/rust-std-beta-armv7a-none-eabi.tar.gz": "b571a28b02107adc227fe02878064f44e5d23bcc91b530f57b4dfa43a4c3ec1c", + "dist/2023-03-07/rust-std-beta-armv7a-none-eabi.tar.xz": "854433b082a6bad442c1b9cc9708357b779cbcb84de65f832cfcba06a6088157", + "dist/2023-03-07/rust-std-beta-armv7r-none-eabi.tar.gz": "04c1479778038948f30d2fa87a18562939569422fe57e91659f9f0a5e8ca7f5a", + "dist/2023-03-07/rust-std-beta-armv7r-none-eabi.tar.xz": "38d52dc26074ebd93e6a61dbb0c934a66f32dd1113cdd9d32e4d5829ce62e188", + "dist/2023-03-07/rust-std-beta-armv7r-none-eabihf.tar.gz": "14e4707dc514aec378e1aae2949231ee3bbe216164a794e7e6d233db54f13459", + "dist/2023-03-07/rust-std-beta-armv7r-none-eabihf.tar.xz": "c0bf08f5d378955ba15441b5229d1ef202e6d071a243ae7fb34b9f1724fd90cf", + "dist/2023-03-07/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "d9468e5a056478482cb9a85a63aba6d1987026275ed0c8ef64fe7a84ee5e35f6", + "dist/2023-03-07/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "77262a746f577b0e6f9b6c1aa338f90eeaf8221ad70f5ca93500459c1749f3b3", + "dist/2023-03-07/rust-std-beta-i586-pc-windows-msvc.tar.gz": "2c8c95b80e43acb921674d4a9b2986d89dc008e5977a6a05e820adfd385f55ca", + "dist/2023-03-07/rust-std-beta-i586-pc-windows-msvc.tar.xz": "9573dbb30fd7a24d4d7e831f51e6c05c76d856d545ce4601f4e91b784c348355", + "dist/2023-03-07/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "f1861d5b7875a81a11a98a6cde90fe958d1819517de21e377cd05b58eb5dde27", + "dist/2023-03-07/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "f8e816f9ca02c3cc515d07d5b5cecc8c5dcee64b8deb1bc1ab249010664d1cef", + "dist/2023-03-07/rust-std-beta-i586-unknown-linux-musl.tar.gz": "614a80336890ab422366caf16c73c26a7982c2369393a40633eb925113e93306", + "dist/2023-03-07/rust-std-beta-i586-unknown-linux-musl.tar.xz": "e8dbf05a3964ce39dc4c732c5a4bce60cea1764c151b1ed4333e0da858659050", + "dist/2023-03-07/rust-std-beta-i686-linux-android.tar.gz": "34df9ba98cbb7fef8624e921045110d0b4623028a611f5819bc79aef9e611024", + "dist/2023-03-07/rust-std-beta-i686-linux-android.tar.xz": "bef0d789d8d66d0eb69970ee23e4cc966f655efde901db13a4fc9d02c875848f", + "dist/2023-03-07/rust-std-beta-i686-pc-windows-gnu.tar.gz": "c86ba5a55d449af72a4450566a9152edac5fb43ab03d1385779bb4ab62255f7e", + "dist/2023-03-07/rust-std-beta-i686-pc-windows-gnu.tar.xz": "8dfab1eb07c9391be73cdefd892f6d7ca72be99a7fda5528906343108c5b5503", + "dist/2023-03-07/rust-std-beta-i686-pc-windows-msvc.tar.gz": "99c56608131dbab4775a35ea16d50149af37ea57ef0c0dd52bec2639dc3bfce6", + "dist/2023-03-07/rust-std-beta-i686-pc-windows-msvc.tar.xz": "1983fae15ae3e5480efb1cbd0fd0509e863eecdc456e50899bdc6cfc2da580c1", + "dist/2023-03-07/rust-std-beta-i686-unknown-freebsd.tar.gz": "4652d56693b3432446ebeb5b52399b27d95066c0085a24a4ff5b96a2116cef95", + "dist/2023-03-07/rust-std-beta-i686-unknown-freebsd.tar.xz": "a89a970a699864eda563170f41210ae3692059f8b141d532172907ca1456e8a4", + "dist/2023-03-07/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "0d6b69445aa064ad6c53a26b52011b4533e83c7398a9ff4a10c29bd2c5f1673a", + "dist/2023-03-07/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "4cd1770586a92192da3aa4fa8a846412db8377fe04ce5502792c67d8d3bf9278", + "dist/2023-03-07/rust-std-beta-i686-unknown-linux-musl.tar.gz": "b7c0385692fb7218dc16e3935b6181beeaea1adb731a5ca2dc876a3fa825dfbd", + "dist/2023-03-07/rust-std-beta-i686-unknown-linux-musl.tar.xz": "92c608fd3be1bf98ce343f4b42e187fa1182560bfe10a2c3110037b0600f611c", + "dist/2023-03-07/rust-std-beta-i686-unknown-uefi.tar.gz": "97703dfc96fadd27af79faec3b9b14f5e64549870c5451e8ca5023dc97a7253a", + "dist/2023-03-07/rust-std-beta-i686-unknown-uefi.tar.xz": "7470fc83530b83ad3bae30e7185ca54811f97629ef64b70d3fc2fb757639abf7", + "dist/2023-03-07/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "54f2ff0de486ab6e6ed6dae72d798e1fcd4653b7df1f8d4127eb6a6396572081", + "dist/2023-03-07/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "fb3c1a6daec2ae77de369ef6bd93955d67e70b7b2799a286d2332f5b7d46b715", + "dist/2023-03-07/rust-std-beta-mips-unknown-linux-musl.tar.gz": "4af2c66e9e2b3d4003a47aa638177b256db683f7945fd4cf02122c144736045d", + "dist/2023-03-07/rust-std-beta-mips-unknown-linux-musl.tar.xz": "8f3f4385b4a6fb9f8cbeec20b7f7b794d1374221bcab5c2a5aa59d94acdd6855", + "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "ae14ec5c0ea8629de6b8db2a83a4ceb08be6475a07c89abbd8697f72f9d46427", + "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e2ddff933278d45c9e2d4e6734babd3b6a1e104325d814c8faecc4a51d197a96", + "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "d67f7fdfbffcdb4daf134209ae62c051959ef5b450ce12f6ff87b5d7f2d69c7f", + "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "f5ecb43d0445a03d4677b3a8997f899938755c877bad2262dd88f1c5b2960c1b", + "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "9a9b36ce50e1167259c43d5dd8669ca26831bf7d2df6162395df6f22b3c3b7cf", + "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "966d074243e8bdbacbe85fbeae546d9d65b3579015abf18a458798f16ad6c940", + "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "a64b67a50418e8ced6333075541a30f7272fe11f11160969c92efad447c94ebe", + "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "f2fee3ae76bb483871b23a4ec1cc22cd89193e087d5389362385d21ddd162392", + "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "f659bb468e1e4a44288953e654808452f1b08bc7acef546b72e0b31fb3552503", + "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7be5f817c2cca408804be8f0168e60a407d6088b3758688d2e8a79662b26b340", + "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "2c988d57deb6d9f88a6ff4180b41a65bd2a69722b6d3dd7a80ecc3bfc1ebda0b", + "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "8e852cb52c7189a5de0274bc592a720ab1d657f39dd689aea0c11cc8d45b7441", + "dist/2023-03-07/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "24db414fdf589e5c686e0c1441b061d82b480a305cf7926d7a54f3ce6bcc48da", + "dist/2023-03-07/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "f4a90b86b5cfd448c5b7c1b29b99c0f016d64deeee7bfb98048d8b0215f15174", + "dist/2023-03-07/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "9c04535d6ad8a823e94e98e3d8aa300ae7181501dfb9819ddbe072ffefe2df98", + "dist/2023-03-07/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "121faf0e67f1fbf609b6f2746c343b2a7fb7efaf0a7129a9d867e8d8c52d5816", + "dist/2023-03-07/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "013b5968c15c7257932ea79c8df23dafdc20606a4dd6e7b7f784d56d59831835", + "dist/2023-03-07/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "26abe47cc533337847c021c08fcb88ec77152b5a33500ab948fc45c8bdab23ee", + "dist/2023-03-07/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "c72d7e9f58640933bbe5dc1cd7b0ba87f5080ed397099d04cacad992a989199a", + "dist/2023-03-07/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "4ef96cf7f4ad93c41b69e9f6a48937cdfb307d7ec65ab2f475707680f638848a", + "dist/2023-03-07/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "b4d5fabcc593313b41bbe1a4a201d2acd23f07ce249b6414bb5fb940df519d90", + "dist/2023-03-07/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "537d209c9ea5a7d7750206612b353d33d54a5c55af45c4e8e4f113c6d561cd5b", + "dist/2023-03-07/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "8307dd2783e0ccefb27cd645ab53717c851e91c5c5a2e466bc2ebe00f23afeef", + "dist/2023-03-07/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "f2bb8932f9d2a0e51caf64367bb34d1c30456863d3933c766c69be50c0474ff5", + "dist/2023-03-07/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "300892f31875cbca564b54124e85fada8af945247c3a31049e6000494f3a633f", + "dist/2023-03-07/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "ebeb2d2bdace58faca8f5d8d3e06581c30f18ac7e0e096d03fd4444a7ca9b7b4", + "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "62d9e27a3c321bed86839ce6a492e28aa51b1d70bd1b0ff0d6cf8784ee78c8de", + "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c876705073fa8735fb3b89453a4cb00c3324d3e8ee570acf3bab21ab0ec0d240", + "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "97751b6d399463e9dbdae41979d0e6405d0faf90ee859d2bb87787a4146420e4", + "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "cde9469f915b2f37537da5a596ab75eeeff64affd5f26619cd59dab06c03b13a", + "dist/2023-03-07/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "000796b94967c2285fa240542063743d389595aa64a58a64145ca093ae505222", + "dist/2023-03-07/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "3ce3f15333e074060c6fc97f40bc2d41d582744df97c1e4630839a34397e793e", + "dist/2023-03-07/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "8a44c200db94509b83ea2bcf3b5ca7b8ff1f3c7aa0c9b7942ee3047b619aa161", + "dist/2023-03-07/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "6484f92b2d2793c47f1665d4c0bb93fe64359a3cafb658957bd3ffa33c3753b2", + "dist/2023-03-07/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "d60be45093cbbd1269be0dc0e73ccded00a9b72b65fde8c8c5fb72d79cdcdcf9", + "dist/2023-03-07/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "8b46c3bb7a74116d8dfa69fa46cc70b4771c6a28d73c501bc935573e1d06cd20", + "dist/2023-03-07/rust-std-beta-sparcv9-sun-solaris.tar.gz": "5caf2b9c9dd509ef50840484b577b6ddac2cda32519b75a97053de85340439df", + "dist/2023-03-07/rust-std-beta-sparcv9-sun-solaris.tar.xz": "bc00a55394520283826011467d9f27c74369d47e3d5bd0f9c7b7cc2f2cf74cac", + "dist/2023-03-07/rust-std-beta-thumbv6m-none-eabi.tar.gz": "38ab6ccd205e1ae9c7599482927bfe42096ad02cef8660bc9aae345b1081e723", + "dist/2023-03-07/rust-std-beta-thumbv6m-none-eabi.tar.xz": "7d605918c0bf111a02fec102de688bee0f2f18e3583c004571710421741224f8", + "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabi.tar.gz": "cc7b6933e5f16bc828b446289c561d9810a977a322bdd9e406fa9c5b3e3e925f", + "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabi.tar.xz": "d42fffb2fb88bac3090a9d99bfb91405f9bac5b09b88b286f74a85deb31adb2d", + "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "63619f93d1047979d90cc37f6903d4d34c28c793f5d07d448b8f818049c0694c", + "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3f9735ea8a2b340803e95d55bbd1d510b501e4cd5844a9334ee9cda5733f17cf", + "dist/2023-03-07/rust-std-beta-thumbv7m-none-eabi.tar.gz": "73581e242b9f002eb36dcf05594859419cbe77393a8b21e8e1f447aaad05b0d0", + "dist/2023-03-07/rust-std-beta-thumbv7m-none-eabi.tar.xz": "f582f14891696a51458b3fea2db8ad883012aab40a5d8cfe97b420d0ad7ab901", + "dist/2023-03-07/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "5036157df192a76a3bc5084e9c4e53d9151871c1bd86851c361a08d09779cb0e", + "dist/2023-03-07/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "6b85161caf4a45bdaff3f5428fc41b7bc81a216484c755b7cab297a4914b7c7f", + "dist/2023-03-07/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "b749800ef87d357cc010ba46305d6603a40f7c52be3c1778e6a88a2956b89bc2", + "dist/2023-03-07/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "622dcf6bfae396ddf89dd0935a3269cc4f86f5ccc7c83982a75b915600f19733", + "dist/2023-03-07/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "7ec9e547fc95900efd3f04cb6f76213be5da762d997c85e8ea8434cbc0c0eebd", + "dist/2023-03-07/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "358fca90a80aeefdcd829aa6d3a027d81ceec010cc42aef971285c7d31699fd6", + "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "4d87df24f8c466cf2193eec458ce4033926088004d88b3ec4b9c74ed1d137a8a", + "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "65ded045c0615432a6017524c24da2e66b3ecd83e8869e382a00f2407fd06441", + "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "f8e081253423ac6fb29d502267e8fc22a3409965bebdd331dd00420ba609511c", + "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "c69a893777fc2acc407832752ea51d4bad5c4741c4a256172e4ebddeb5f939a7", + "dist/2023-03-07/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "28a8d21a98af1f950bb3f62d6fd124bc2fab0c0c27a419c1fcc1a84d31191b8c", + "dist/2023-03-07/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "b0a774faa4acdbff7d7581617da76e759e073a8d75b435373d9737c4300a178b", + "dist/2023-03-07/rust-std-beta-wasm32-unknown-unknown.tar.gz": "2a785745d3129a25441572d221a30d4108a35abf3bd73a387a5d65a5df82ff18", + "dist/2023-03-07/rust-std-beta-wasm32-unknown-unknown.tar.xz": "b5a50098ad047748644c7f510cb2682c52499d12f02a1e94c59a4f904c8002e6", + "dist/2023-03-07/rust-std-beta-wasm32-wasi.tar.gz": "265fa8b315a5d39a35fb8d32d5e46c3c66f9608992a3d708ac90437818cfed45", + "dist/2023-03-07/rust-std-beta-wasm32-wasi.tar.xz": "26839f3ed020dbda8ba893492cf504d565e7e1af7cfec5ad76053443d1022839", + "dist/2023-03-07/rust-std-beta-x86_64-apple-darwin.tar.gz": "8322910f96d5e206fc3ad237b4cf456e9fc2be0cbb00a57bfc2625126fe84d12", + "dist/2023-03-07/rust-std-beta-x86_64-apple-darwin.tar.xz": "3b1d0288890649121ed4487ec6ef5986913bcad5d224e8fed6feb5fcf56a3b2c", + "dist/2023-03-07/rust-std-beta-x86_64-apple-ios.tar.gz": "ea0a805d90b4b18c0b525faf4eedd2827d1f009d3c7a5cdc084db60c54e86d72", + "dist/2023-03-07/rust-std-beta-x86_64-apple-ios.tar.xz": "86bbc9cb184cb3c18a0afa1b982e951ee1e2569fca23ae7f85efd29f26e21983", + "dist/2023-03-07/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "f6bab7e24104f142c62f6d12585725bca24496d45888b22b07d2cc50f2f7f11a", + "dist/2023-03-07/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "20a1ae7636cc1dd9daec73818ecba60c60162d2a016822f1d3e828f55fc4ef9a", + "dist/2023-03-07/rust-std-beta-x86_64-linux-android.tar.gz": "78e7cae3d09a115fdd447bac210a78595076c37287b6dc142f9c363d207e16f5", + "dist/2023-03-07/rust-std-beta-x86_64-linux-android.tar.xz": "f37fcdc813462bcd94b0a06e38e665da9e5c1b5704cd029a23498c003a0df0a2", + "dist/2023-03-07/rust-std-beta-x86_64-pc-solaris.tar.gz": "afb0facbc35bc80c9f23ba59b9367c95b907c944aa5e1eff0fcf9687ca1089cb", + "dist/2023-03-07/rust-std-beta-x86_64-pc-solaris.tar.xz": "c771fd343a9a2073a8170730936153698d94aed87aa15b52a04075a6bfedd4ba", + "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "c753b3450a584ec7614e20fe308653c2451cc1910de76da663ee5c53a451004b", + "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "0d072a92ee2d33dd6b6122d273ba8cdbbc7dbc4cf090ca7abbe08fbfb16d5f86", + "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "de23d40c1aefa660f1411bb0c17da4f16b093244c0d515861b0866aed1e06b07", + "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "6f7b6070ae06074f338fc9eae327bf219389b5f88ee7ae07eb1e290d277b0f8f", + "dist/2023-03-07/rust-std-beta-x86_64-sun-solaris.tar.gz": "f2d68b5119525110c29dbd19a747f3ad632f45facee5c437e6796a2a213c52d3", + "dist/2023-03-07/rust-std-beta-x86_64-sun-solaris.tar.xz": "2da196278cc5a2eba2400d5d2b13fe74b65e9daefda0a6231684baaf76982147", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "c922f51ac5c80630d9cf2b1a0f770bcd1c1d74180a716b9852d37a6621035c38", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "b6ae7c3cd80b12537d0802444be97acf9be5072c058d025ced07398b0651f45c", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "2fa8a0fcba9ecd4ac6c47b22091a4f58708f96197f95dcc8075e80a4256fdb0e", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "025575e750bc2e1b43e7bf288a87059c96629d0d7290a57cfd0e31f2d0efb9aa", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-illumos.tar.gz": "8cfc61094c5ea8eec46131c17deaa8dfaa900f75300b996abd167f527defbb3f", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-illumos.tar.xz": "2e7c57376dbf890dc7d6bb7a0b555ee791b147aea4924882a3a94f9b75347f43", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "4840a693353f759d2d9e3fa40df97f200f27106159a9b126698a6ce07c3a117c", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "9a13a8c8e16028d0e07608da8fbd0ea5b51d9d425230712adcbac679ef5fef9d", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "0ac015df12c5212ac61b5a691d982a4fd64a8f77653b3d41e47da974abecda9f", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "bc12d3599f60a5860a15958ea7d4dc537d64802a23bc75e37a7381d875d3de2d", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "10ae35f994f504db3f58f098e8af9bc15f0c8e878b0af8487b6975846dcaf5ee", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "6d46f12168472f6a82980987d02b7e646a0814219c809ce04c352048be0a2981", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "978d7e3df8d6a16af9461eed0fdf79745c8a3ac91dc7e53ac4670e1991916e59", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "f936f6d186df0efcbf1655e7d2436bdebf5cd56ff811802c9ff753f20f38579e", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-none.tar.gz": "9c76650dd06c6d679716e4215259720ff5abed7731621617b9a785bb1c1f3c88", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-none.tar.xz": "4ec0d0b2dc4d163db2967df2f16dfd822adba2d85e85fcb21984c84377b4a5c2", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-redox.tar.gz": "701342db468d8bd5c08b962adf3b2c34d83a10fe81936d3b91937b5667e3f5e9", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-redox.tar.xz": "1c32cbb84bf8f967de3fe71e63c3c0d28c799276d9c2b5f2b3afbe87e57f026a", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-uefi.tar.gz": "51492e36780f026b1485d2c0394bc232d8825f3317fd438b1f8eaf9b8d50712e", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-uefi.tar.xz": "33e46267265e9ec7394932b197c598d48147a119bd7346614714590181c84884", + "dist/2023-03-07/rustc-beta-aarch64-apple-darwin.tar.gz": "16927a64c3e0737274ebe4c8e6423977d5f2d684751f678fd2dc5c6a6020ab4b", + "dist/2023-03-07/rustc-beta-aarch64-apple-darwin.tar.xz": "66f758933129e0b1856b477f364e04187316227b4853aee8a5f95f6c7ad60fac", + "dist/2023-03-07/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "10a7cd771929aee13937bab01ad1e6d19998cc4ef58816ad8306539140fe3dfc", + "dist/2023-03-07/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "1d9ce8c7728b1831ce564df9a8ee9502ddcfd83c764d0f8c5b941a9beb570fb9", + "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d75924fdcaa76b064d018e612457a4f960536c51767f46fe20d5e90d41424d45", + "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "1956f0965e3065a5901f935c42b10e07783ca33a2a8b6f182a5104edc4d73a01", + "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "40fbf2a72485dadf04eaf2a128f631c02542cb53f0d2b2c26369e8b8ee08463a", + "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "cb7f9812a09ec7397ccb67f36484ce22425446940b65cdc4c72e823a6fab5ec1", + "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "bc95e80e02e822913eadf5319253e7422615468db1c9627d394992319c3e4d5d", + "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "5b089b4b531cbd43909518093f6cfb1e5d4df138ede86ef7cc0e0e1053a43452", + "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "030d2ec4494c9139966cbb833c1616a78b973f10409defbb39f936652ef97449", + "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "2b2a728780b1bd30ec0cbcf014cb8914ed423a46a97f330c23b7386d8aec2ab7", + "dist/2023-03-07/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "2406baa5db6a46e51c79201fde893089ad16f31a17b117509774ee76f16bcdad", + "dist/2023-03-07/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d121bf988fe4225d1cee4b452a0d5aa1620c990456dd9002c0af179802dc33c8", + "dist/2023-03-07/rustc-beta-i686-pc-windows-gnu.tar.gz": "eb5d4ae35799c3ddacc77e946b9fe8c1ba88f193c14c58ff23ee7ad89bdc6d9d", + "dist/2023-03-07/rustc-beta-i686-pc-windows-gnu.tar.xz": "1aeb85967f6de2267024abab0bb46dec4ce3bd06e687af39745cb556c37a82fb", + "dist/2023-03-07/rustc-beta-i686-pc-windows-msvc.tar.gz": "be2b29bd8ac4214eb5dff5f51c30cabfe859bc02b994c87cb139af50889abced", + "dist/2023-03-07/rustc-beta-i686-pc-windows-msvc.tar.xz": "1c097877d03021b975f2968bda73301a541b7989eb217537ffa3ae079e576c5e", + "dist/2023-03-07/rustc-beta-i686-unknown-linux-gnu.tar.gz": "3066f0d3b0e0319c8e9bfcc2215bb16729611563cedb976de0356a050ea68357", + "dist/2023-03-07/rustc-beta-i686-unknown-linux-gnu.tar.xz": "3908a8675f8b5743ce407e12cd0a32f0144db9b38bb49f05c47e855973d1e8c8", + "dist/2023-03-07/rustc-beta-mips-unknown-linux-gnu.tar.gz": "7aad6a6e37fb7f4fe835c2bbe7d1deb36ef973b7c94f3969b003812f87a92ff0", + "dist/2023-03-07/rustc-beta-mips-unknown-linux-gnu.tar.xz": "29e434023a1d94aaa5003723e2bcd31588d674f2ae243109e34f8e88e141c58c", + "dist/2023-03-07/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "4b2e92cd5a01df031060d03d088829056039951ce8b7edd9549944a6f567e07e", + "dist/2023-03-07/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "7e82c3f1a6d5175e452abd4f321469063cb2007f9f33cb3302a5745f985aefb5", + "dist/2023-03-07/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b9fb2eb2f43b7479efb227964141f3beb29db829f449830ee41ac83280366ac7", + "dist/2023-03-07/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "c4eedd1aa5ac1532387a3091525d9d94fa7979002e0399b351bdd8d3bd064475", + "dist/2023-03-07/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "03685364b7750002a9a88717170c4330052c0838de82727734ebcb2d8b0466bc", + "dist/2023-03-07/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "13834ad521e7a3439c56dac58a548f816a60cc2b4f0d25952fb610b0245cd141", + "dist/2023-03-07/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "840a15c851f96e9b6b662d0b39c947b922e54195b07822ab6b1e13d5c8206a32", + "dist/2023-03-07/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "5721cb8347f4e9e546a59cec5c89ff548a2dbe867e27107678da6862a435781f", + "dist/2023-03-07/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "bb0c56acb9bb9940e970f23649f0d41338950f2e1c97cbca5e2de673069dca54", + "dist/2023-03-07/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "89c102653c6d4f562ad32fbc2d1b82ef38917528a7da6a3219f7b232dac62fcd", + "dist/2023-03-07/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "7ca86f54a307ec8e4751a58d541745c900813ef9b355ba21442629ef6d965ea1", + "dist/2023-03-07/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "c88a9c0581a8e3d119c57b9825ea8052e448871ed9c64f7530528e7fc833acaa", + "dist/2023-03-07/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "48f8abaffc106eba05c903ec250aeff17a71efa88702459da0ba8be58e62c8c4", + "dist/2023-03-07/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "04c176b55b9fdb2fc123e1e012fb8e2dc3bee74861b6cfedf2c1ffbbb3320293", + "dist/2023-03-07/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "a908e7f868fcd71050f57e08d15648cd6da04a0f9d150d87739349fb9c87a515", + "dist/2023-03-07/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "75062df65fbf89ab1d5344a3471e2c6322f9124fb447b32f634fb6d41695d5c7", + "dist/2023-03-07/rustc-beta-x86_64-apple-darwin.tar.gz": "df5224bb128f668474b9702457f5a349144b3148f44ae77109c7ad78800a4c42", + "dist/2023-03-07/rustc-beta-x86_64-apple-darwin.tar.xz": "9d27f437e483025cbdb69804f05138ebf181dceda8d32a676ea72ea4f27e69c3", + "dist/2023-03-07/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "a7f05d2072c3d3eb7ea88c09ec24a2ce0007ad31df5d3405c6766a68f2fd8ff4", + "dist/2023-03-07/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5e6477ac67b7db05caf15704541db112846415523c483df123d5f566e33afae4", + "dist/2023-03-07/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "3a9fd984f8a6673494859dce2dda6be7293effdc3ff7b4620b1078ba346150eb", + "dist/2023-03-07/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "5a12779df3e03ecb9ec334c02245f4dd779a4763ee789a9d6c72c244fed5b444", + "dist/2023-03-07/rustc-beta-x86_64-unknown-freebsd.tar.gz": "dd04e308e72a9cee60db732a17f12e1acbf279fd07efc232648087b765338f44", + "dist/2023-03-07/rustc-beta-x86_64-unknown-freebsd.tar.xz": "1dd44474ba9956abcdb0aa9d50c39fc7dcc3a78cd56450009bf4ee10cd94ef2e", + "dist/2023-03-07/rustc-beta-x86_64-unknown-illumos.tar.gz": "0db8082563772e480dfa71851182fd8a45cf6776d486e02204d92af0784c86a6", + "dist/2023-03-07/rustc-beta-x86_64-unknown-illumos.tar.xz": "eef088e452e105bffe4d28d38d1eacd4982253f0d59cdeb1f406068961699e0c", + "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "b767ffb06f21b1be530d79a81d8550680d15fd511de5cafae6da9da71017362b", + "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "d62e8956025dca9d6a9259cc8a35c6d364d161648adb91b50f1fe7e2aec5eb1b", + "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "aeb32342fc36171ae54b8677348dee02b10207bc85da773a1c7bacfac5e736fb", + "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b051ffe45858f1ae2e60461183e4181a1b5c3fa4b349788416fb80b3e3fe39ea", + "dist/2023-03-07/rustc-beta-x86_64-unknown-netbsd.tar.gz": "2e5ed0ad450602ce32de9509e5317b1b205d4b715f716befb0389f6f6ad94cda", + "dist/2023-03-07/rustc-beta-x86_64-unknown-netbsd.tar.xz": "9347db918ca8139f0d816f297d327f48039f02e1d9d9f443fc0f46fb260c8901", + "dist/2023-03-07/rustc-nightly-aarch64-apple-darwin.tar.gz": "034c90c20d39fd2384b03ad2a756d3ca28a7447423bd709a0ade19374aa0fb05", + "dist/2023-03-07/rustc-nightly-aarch64-apple-darwin.tar.xz": "89d6d968fd5e55a950a798f06a09e1a776cf11dccc94b8123c21c55ebf55e9b7", + "dist/2023-03-07/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "809733a64b50a7c9c637afb442e45c4424a0fec96d921cfb0c8a7b30fa52edf7", + "dist/2023-03-07/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "03057ff6c4ae76618edea292f49abfcdcad09615a6164186348aba218936c3f0", + "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "e34521e27196fae399e0cbec28700ac409a829cf365bf5b9a7dc5530af61b93e", + "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "e17a9773d58ff0f48cce6c86326cbc33c4e0e8ce08f1a6d475481af9771ae6d6", + "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "01fffcbc734b7de28773a658178534a2cd4d262b156161abd6e5d1d471b45181", + "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "84c0c9d65f00f259df87e78bbe03d0f31075e70b71c587ca580e63604ee654e9", + "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "215cc518a7caacd106ffaaf28f709d1ddb3b4595acdf8574866d4e351576330d", + "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "f50d088adf616f3c25d095254b93d9032a41e5c6a3906afee959b223d6205dfe", + "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a902efadc47040841653e67f918814a16242312c79ef11c10d69ba9999473c88", + "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "d608e664a5ce02b246b6b00910bdcb5f09e565e41cefbbb8efc579ac9a73c810", + "dist/2023-03-07/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "9e8151095f851f71c1d72d41e4ac63ee0dcc81d0f172ce9df4143b6499047aff", + "dist/2023-03-07/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "285530c33e600a4df44fd06abeac8e48aa5c084386c4cbe78e797c54f85d01ec", + "dist/2023-03-07/rustc-nightly-i686-pc-windows-gnu.tar.gz": "c0e245e17691d38d9f69164e5d9e02d08b5c2355f6fa9cea4bacf50af672c67f", + "dist/2023-03-07/rustc-nightly-i686-pc-windows-gnu.tar.xz": "d0c0e699cde96fb23ad5bcc7a8dbf94c86271404b72055bd3382eb29ae4ea85a", + "dist/2023-03-07/rustc-nightly-i686-pc-windows-msvc.tar.gz": "b083a065a973394293c11369199385a96d79a6cac5c9d695848e7ac2e51507af", + "dist/2023-03-07/rustc-nightly-i686-pc-windows-msvc.tar.xz": "b819b9af08383249f99f0137b636ac42ce84e3e5220c9e0fc1d9e0d348dca54f", + "dist/2023-03-07/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "7337d5bc52c0e18c24546b04777ac24461b34e31a59d7df1611f70aee483528f", + "dist/2023-03-07/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "efaae84475ddb1845fca470d6d77d842da4e2ad0cca0b2c1e9210c6fce3ff08c", + "dist/2023-03-07/rustc-nightly-mips-unknown-linux-gnu.tar.gz": "bd12029bcf9539959c9c9451093cf51ed9db6c7e26b9b9a3bf8617e481b9f094", + "dist/2023-03-07/rustc-nightly-mips-unknown-linux-gnu.tar.xz": "b9ea393526c68b9b502d81387cd4a1db7eeddad61467d2442be7c30d210727d8", + "dist/2023-03-07/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "997b37b199cc270b5a832aa608d18e0005a510efb587f154f899a22fb7f13639", + "dist/2023-03-07/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "e66332078213bf0cce845605d2f7faf28d859e3a98d12d61737ef782a9bdb187", + "dist/2023-03-07/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "8a7cbbeb0a9f82333068b51c49d33f694d91da327b1169bc44e9d570840d48d8", + "dist/2023-03-07/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "5eb5e2e270a4a475ef2933fe34c764dc6cfaaae423b0d1acb5313fda970f98ba", + "dist/2023-03-07/rustc-nightly-mipsel-unknown-linux-gnu.tar.gz": "3140ecca2db80b80118a08cc3fc7ac2989054338525bcc1fe0e2ef1fb5f742bd", + "dist/2023-03-07/rustc-nightly-mipsel-unknown-linux-gnu.tar.xz": "0432d418a81564af612a5dac562d7f4d72d7a18ac25260ad183609380efb6bc5", + "dist/2023-03-07/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "5be5fa12eafd82618c1f3f611351f23af1150c48b5e02f80f5b4252ec45c11dc", + "dist/2023-03-07/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "c288c46b8f077ee604d6de6286dc908086383be91ba17700c3f6273d064c6d82", + "dist/2023-03-07/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "de3fe2a9c4c87c5d622a1375dd4fd68064bcd2e5c36dbbc92b95ee42c8ad839e", + "dist/2023-03-07/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "b2fbb76cc9e323d0e61d927d7aceff561074b6dbf9907ed3c8dfd867d1308bd8", + "dist/2023-03-07/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "f16e202e7e2cfc3a47a0eddd5271fd3a9b7bac5f3c476ce619a249b88cc3ef0b", + "dist/2023-03-07/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "61a1cc7f9ce2e8d8ce62165ae7e8b8a53d5c78265641553305130f7a66c706ea", + "dist/2023-03-07/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "25ed59822afbd23edc354adb7e3bc361be9170ddd44fb15d7434e7240a66637b", + "dist/2023-03-07/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "fdadf6c8d04b99094385b4678015f23da571c3cc134b99e96c3964b15d91d9fe", + "dist/2023-03-07/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "b84099f98efd9554a005f8b6d8f15dc9bcd60f9f37856174306873631fa7597c", + "dist/2023-03-07/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "608f5a3a1628306618126f94349171566d9a38f14f58875ec1b1e990bd7b1b20", + "dist/2023-03-07/rustc-nightly-x86_64-apple-darwin.tar.gz": "4d8b094bf5c608b55e5b618838dafff4b701be093d42aea388c998c2676b226a", + "dist/2023-03-07/rustc-nightly-x86_64-apple-darwin.tar.xz": "f11249dc7fd5d208b10b9ead00dc8baa410ce92f61f597e3a550c138e9145413", + "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "db689e50dbef48555609217d09205cd1e397770469a82a9c0ad1f2cf1dd1643b", + "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "36160f7b9a98a463d4e62ed18ff59f5aa34aedf25cf7a7bbd1e4f93dfbfc4a60", + "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "0b10bbbf73fa9a9524746b080d44bcb29d31f013ab809b4c06a71e626f637b4a", + "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "a96259b26388fbf7907df887aacd8059f87207b46bb84ca9b87c460040a17d21", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "0327b112309ab37508c5bd814a77a50e8eb86b19705758ee0a3c09cc560f89cc", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "a7715f358798fc2f78ae6cb08b46f58ad577b91d0aa286893f8f51fda6b2de57", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-illumos.tar.gz": "ed8d664f8609211b3eff0a606f1d5b5f46eb8ab0095df626a26c3abccc518fab", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-illumos.tar.xz": "10badd3e994e93bf48ff1aafc7c056ac525afd12ac4761c0be7af94e361faad5", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "77b7bf994db683057ce94871fb288a24ba41d9a8f5441dfa9a39f3e772f295e3", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "738db7237b08938d978a00b5b972f4c52f36a128ba103ddb67318a905c7e2d27", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "50c57bbf49ec12092dad9de0e559c18f2049de07a0edac4b596a71a2f25a5e0f", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "31af1fbb0f1288e6d7b8eb594cb1936257603038c1ce8b89399056f5d3e1e9c4", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "0a9e395f0b74cc945458d4ad4176567e86cfded1a594eaa485baadb4794dcb64", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "26ff4a12db2b583e2e0b87aeb3d3eb9d1edc3478bfd40ffeb7ebdbfb8d8b2987", + "dist/2023-03-07/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "498c7ca27319868d6d2cfb9448b516de1a12076523f092d6c0df10848ba73ff5", + "dist/2023-03-07/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "eec9591d608e13c34fc8108fe976ae2085d688416d82c71bf18f3b00e35a1442", + "dist/2023-03-07/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "e9822c7e59218e75af96657bc8a5c3a20c77209f6f1d8861c626aabe7ba9a61d", + "dist/2023-03-07/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "dbad704c1fcfbd8562f366017c514aa90874de6028a9b41764ab7d78a72df6bf", + "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "5529210f57a0128889c19491846ff7c6f214d3a81d0619ee8dbd840f5f6f84a7", + "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "d59160d2f737322d401e864ae6b7be47f784a334c7cb378a0bbc2769e975945a", + "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "ab98e6c8fa7998065e0aaf211559d71405cc6e1910e3799889a27bdeea8c620f", + "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "04ca84fc64c1d211bd29f99b278d9072babbd1e0e9009d9f6f8f1b05f93a70ca", + "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "e80942fde81d3b54c4d0fc73576eebcda215535e4d80093f2a68f434958c0d9a", + "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "a9f10f9a51d3e3564f40c65f6d50c8ef67b4e074981f06f4d3b66aa398883f42", + "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a5566343b6e3abadb152cd4a325735830aa9a60d5f2f87ef1aff66bbde276b14", + "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "9682e6c4a153d5083b0b360ed9248772da89f05f1142a6f297fc67218b60f298", + "dist/2023-03-07/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "51c14ab7679c23825e3a5b9637035768fd43f1e2787a12e431699710f4324998", + "dist/2023-03-07/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "f44893b879649a288c77b826e7e10202a2d3a5b8a8b123d8a030e69671a3ac43", + "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "7d5a0e567d8efd65b06b4a75ddc50e7bc2e36b42abaeab15147e970688c0bd07", + "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "541d5cb3d7beff1c0f9f2ea4a521303a372c2b6f4476d76bcfce4974a2753dfa", + "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "ccc65022f10cf0d7b8228806742c5163cd77edfcc2624894b96b2c9d6d974da4", + "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "fccfae7200edd30cd1b6083d00a400641b77e0a4a6e3bf2573710964c896c0d1", + "dist/2023-03-07/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "eed06879dacc571c289745a943de9bde2e39bee79ab5a5de0304fdc00e116855", + "dist/2023-03-07/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "cb1ed1cf09ce5cdbec931ea27b6fccd37b63108c780ae21c1756c68e0415c59b", + "dist/2023-03-07/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "b0681834694c5aa27c404d2328a5ce3e3dcc8a0b146fcd9d47113655cf94c948", + "dist/2023-03-07/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "a246b3e7c6ad436ad7523607bcf3a1fc42a66dd9da6a401fdaba5724fdf6801c", + "dist/2023-03-07/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "fa5b4d24c046b01b981fb81540155af5677490f2ac151418fa7791ec0f5aed56", + "dist/2023-03-07/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "b28148883461e905440ba25f755dc6a46c393a69a4cea48044e376fb90caa44b", + "dist/2023-03-07/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "ff37f00813b2ef0c206fb66cd383f87a089fad6a3746a9d62b27109557eb0097", + "dist/2023-03-07/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "2132cfd61404cfdad4e21ad95066836c77863756d46abc1fd2b702f46b3c7fac", + "dist/2023-03-07/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "89d1e41fd9bdd76c15faba83abfa1ffdadfffb6cd1b49c18e2d1333856296ee3", + "dist/2023-03-07/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "2353107ac3875f9cdf690b6684941c2def1c240416208dee58f58e78eefbd96e", + "dist/2023-03-07/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b6e0882de92b73d540d22df393750646487dcf12c11b0bdad01265ce5cd6275f", + "dist/2023-03-07/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "c64967a706e7448f97d40b50356672b03f2731fde3488084007bbe7cd07409a6", + "dist/2023-03-07/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "d7d829f5a23aa25b320cd4f4c12d2db11d7e36c67a9396de7426933169159b62", + "dist/2023-03-07/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "1080d035d29fb9f8e1c007796e38164261ba19d4362b847d571eb7d3a6281d5c", + "dist/2023-03-07/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "874d841241b37072a6fb6c8d70f0afc9535ffb47793270b3a2a5c96ba46b7ec2", + "dist/2023-03-07/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "7ede80fb9a1aa27380d764d04e587a30fb6aee36138b145e32d518cbe8ec95b5", + "dist/2023-03-07/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "e1ec7d8b92740b0dff06e9424ac8d08b64e4aa85c5e8d46f9234fdeab5ad5e44", + "dist/2023-03-07/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "9058714e2f253ca681b24308a59bee006f636dff0b7571ebdf7c7687233b5a2f", + "dist/2023-03-07/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "6087e0abf78f2cb49240314cd31aa9bbfca02eb4918db4a2aaaa6758e8364560", + "dist/2023-03-07/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "2c775b1d4e2f3218a1d51f8ac79c63e8c2eabc46106e2a38d5bd1febcba7d12b", + "dist/2023-03-07/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "3a14e2b54773816cfdee1a835d2f758abfaacef36af6a7744c464b0ce5713c8b", + "dist/2023-03-07/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "3f6f7e5b9180f0114781b776a7f1bca72b208ddd102a9e44cebcd501eea7a31b", + "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "c92bf50f2a729af4b045184cd984bde0d97979cf8ae35975a1eaad5d8ae04195", + "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "c62b8f4862d0f8c38b890408c014be5d6d245f2a49d6f31a80c9447bbed4d8b4", + "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "8452a8704cb04ce2deef2cce2d9f2be066c5bd35aef323877ebef6f8f739710d", + "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "e694bb8697679196246f13031a9eef5129b0441a8c93c0292382b21cefab39a7", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "37f7ecfc0ba9314b2ec46ce202973cd7e36062a88070427ced9ffed3ad96c685", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "7aef4412810218743a85f1c7cce423394a327a708d31441441050bc1fcae0d80", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "70701d0bc637c282436e9ef6f18dadcb8068305ac64b1abb802bbc5054ff042c", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "2d8e170259a254cf6b1c5749a681040db70e2603b7231082483f03e2714765ba", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "7241cab5f93fc338fbb07acd2d38e2fa8615c4e6ebb0a53f51ac60c23838845f", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "2742e08cf5900ad3002809c632b8b8962325699307943ba2bafa0931204cc787", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "576c17a72e47fc743d60818bbfefe17c0223eb979cfed3046bf4797e6c2a6d26", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "25026a50665f53b7ac3e1e08b3a5a3a526411c8c18be6d64df6ab23ee0819b64", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "773679226499447a48cd823d324fc906a1d93f3fb5abc137920aa67ece410de9", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "53c88668c3c9ab6df7f3cace825a45616909bb28628ee8636a8ce86b77cf4bb5" } } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 4a3c588b1f0a8e2dc8dd8789dbf3b6a71b02ed4 +Subproject 15d090969743630bff549a1b068bcaa8174e5ee diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 0abe234fc8f..1323f973ccf 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -152,6 +152,8 @@ Current stable, released 2023-03-09 * `SYSROOT` and `--sysroot` can now be set at the same time [#10149](https://github.com/rust-lang/rust-clippy/pull/10149) +* Fix error when providing an `array-size-threshold` in `clippy.toml` + [#10423](https://github.com/rust-lang/rust-clippy/pull/10423) ## Rust 1.67 @@ -186,8 +188,6 @@ Released 2023-01-26 ### Moves and Deprecations -* Moved [`uninlined_format_args`] to `style` (Now warn-by-default) - [#9865](https://github.com/rust-lang/rust-clippy/pull/9865) * Moved [`needless_collect`] to `nursery` (Now allow-by-default) [#9705](https://github.com/rust-lang/rust-clippy/pull/9705) * Moved [`or_fun_call`] to `nursery` (Now allow-by-default) @@ -423,7 +423,7 @@ Released 2022-12-15 [#9490](https://github.com/rust-lang/rust-clippy/pull/9490) * [`almost_complete_letter_range`]: No longer lints in external macros [#9467](https://github.com/rust-lang/rust-clippy/pull/9467) -* [`drop_copy`]: No longer lints on idiomatic cases in match arms +* [`drop_copy`]: No longer lints on idiomatic cases in match arms [#9491](https://github.com/rust-lang/rust-clippy/pull/9491) * [`question_mark`]: No longer lints in const context [#9487](https://github.com/rust-lang/rust-clippy/pull/9487) @@ -4382,6 +4382,7 @@ Released 2018-09-13 <!-- begin autogenerated links to lint list --> [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons [`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core +[`allow_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes [`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range [`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range @@ -4661,6 +4662,7 @@ Released 2018-09-13 [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else +[`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive @@ -4985,6 +4987,7 @@ Released 2018-09-13 [`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc [`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by +[`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization [`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 3158080d2b3..3df13280369 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -50,7 +50,7 @@ a [developer guide] and is a good place to start your journey. All issues on Clippy are mentored, if you want help simply ask someone from the Clippy team directly by mentioning them in the issue or over on [Zulip]. All currently active team members can be found -[here](https://github.com/rust-lang/highfive/blob/master/highfive/configs/rust-lang/rust-clippy.json#L3) +[here](https://github.com/rust-lang/rust-clippy/blob/master/triagebot.toml#L18) Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy issues. You can use `@rustbot claim` to assign the issue to yourself. diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 995dd2f04b1..9ed6627b741 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -519,6 +519,7 @@ for the generic parameters for determining interior mutability **Default Value:** `["bytes::Bytes"]` (`Vec<String>`) * [mutable_key_type](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) +* [ifs_same_cond](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) ### allow-mixed-uninlined-format-args diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs new file mode 100644 index 00000000000..15d46e954a9 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs @@ -0,0 +1,71 @@ +use ast::AttrStyle; +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast as ast; +use rustc_errors::Applicability; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// Detects uses of the `#[allow]` attribute and suggests replacing it with + /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) + /// + /// The expect attribute is still unstable and requires the `lint_reasons` + /// on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to + /// the crate root. + /// + /// This lint only warns outer attributes (`#[allow]`), as inner attributes + /// (`#![allow]`) are usually used to enable or disable lints on a global scale. + /// + /// ### Why is this bad? + /// + /// `#[expect]` attributes suppress the lint emission, but emit a warning, if + /// the expectation is unfulfilled. This can be useful to be notified when the + /// lint is no longer triggered. + /// + /// ### Example + /// ```rust,ignore + /// #[allow(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// #![feature(lint_reasons)] + /// #[expect(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } + /// ``` + #[clippy::version = "1.69.0"] + pub ALLOW_ATTRIBUTES, + restriction, + "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." +} + +declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]); + +impl LateLintPass<'_> for AllowAttribute { + // Separate each crate's features. + fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { + if_chain! { + if cx.tcx.features().lint_reasons; + if let AttrStyle::Outer = attr.style; + if let Some(ident) = attr.ident(); + if ident.name == rustc_span::symbol::sym::allow; + then { + span_lint_and_sugg( + cx, + ALLOW_ATTRIBUTES, + ident.span, + "#[allow] attribute found", + "replace it with", + "expect".into(), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index e8106beec37..29fde9336c0 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -495,18 +495,19 @@ struct NotSimplificationVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind { - if let Some(suggestion) = simplify_not(self.cx, inner) { - span_lint_and_sugg( - self.cx, - NONMINIMAL_BOOL, - expr.span, - "this boolean expression can be simplified", - "try", - suggestion, - Applicability::MachineApplicable, - ); - } + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && + !inner.span.from_expansion() && + let Some(suggestion) = simplify_not(self.cx, inner) + { + span_lint_and_sugg( + self.cx, + NONMINIMAL_BOOL, + expr.span, + "this boolean expression can be simplified", + "try", + suggestion, + Applicability::MachineApplicable, + ); } walk_expr(self, expr); diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index e8531157e0f..a8926b29ac8 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { span: Span, def_id: LocalDefId, ) { - if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) { + if !cx.tcx.has_attr(def_id, sym::test) { let expr = if is_async_fn(kind) { match get_async_fn_body(cx.tcx, body) { Some(b) => b, diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index f10c35cde52..970f5004993 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,18 +1,20 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; -use clippy_utils::ty::needs_ordered_drop; +use clippy_utils::ty::{is_interior_mut_ty, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - capture_local_usage, eq_expr_value, get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, - is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, + capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, + if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, }; use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; +use rustc_hir::def_id::DefIdSet; use rustc_hir::intravisit; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_middle::query::Key; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span, Symbol}; @@ -159,7 +161,21 @@ declare_clippy_lint! { "`if` statement with shared code in all blocks" } -declare_lint_pass!(CopyAndPaste => [ +pub struct CopyAndPaste { + ignore_interior_mutability: Vec<String>, + ignored_ty_ids: DefIdSet, +} + +impl CopyAndPaste { + pub fn new(ignore_interior_mutability: Vec<String>) -> Self { + Self { + ignore_interior_mutability, + ignored_ty_ids: DefIdSet::new(), + } + } +} + +impl_lint_pass!(CopyAndPaste => [ IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, @@ -167,10 +183,18 @@ declare_lint_pass!(CopyAndPaste => [ ]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + for ignored_ty in &self.ignore_interior_mutability { + let path: Vec<&str> = ignored_ty.split("::").collect(); + for id in def_path_def_ids(cx, path.as_slice()) { + self.ignored_ty_ids.insert(id); + } + } + } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) { let (conds, blocks) = if_sequence(expr); - lint_same_cond(cx, &conds); + lint_same_cond(cx, &conds, &self.ignored_ty_ids); lint_same_fns_in_if_cond(cx, &conds); let all_same = !is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks); @@ -547,9 +571,39 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo }) } +fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignored_ty_ids: &DefIdSet) -> bool { + let caller_ty = cx.typeck_results().expr_ty(caller_expr); + // Check if given type has inner mutability and was not set to ignored by the configuration + let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty) + && !matches!(caller_ty.ty_adt_id(), Some(adt_id) if ignored_ty_ids.contains(&adt_id)); + + is_inner_mut_ty + || caller_ty.is_mutable_ptr() + // `find_binding_init` will return the binding iff its not mutable + || path_to_local(caller_expr) + .and_then(|hid| find_binding_init(cx, hid)) + .is_none() +} + /// Implementation of `IFS_SAME_COND`. -fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { - for (i, j) in search_same(conds, |e| hash_expr(cx, e), |lhs, rhs| eq_expr_value(cx, lhs, rhs)) { +fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &DefIdSet) { + for (i, j) in search_same( + conds, + |e| hash_expr(cx, e), + |lhs, rhs| { + // Ignore eq_expr side effects iff one of the expressin kind is a method call + // and the caller is not a mutable, including inner mutable type. + if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind { + if method_caller_is_mutable(cx, caller, ignored_ty_ids) { + false + } else { + SpanlessEq::new(cx).eq_expr(lhs, rhs) + } + } else { + eq_expr_value(cx, lhs, rhs) + } + }, + ) { span_lint_and_note( cx, IFS_SAME_COND, diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index cc6024b87cd..8ca91301472 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -35,6 +35,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO, + crate::allow_attributes::ALLOW_ATTRIBUTES_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, crate::approx_const::APPROX_CONSTANT_INFO, crate::as_conversions::AS_CONVERSIONS_INFO, @@ -262,6 +263,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_clamp::MANUAL_CLAMP_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, + crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, @@ -616,6 +618,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, + crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO, crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO, crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO, crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 080d44e6398..80c22742ba4 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; use clippy_utils::{ any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths, @@ -160,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for Default { } }; + let init_ctxt = local.span.ctxt(); + // find all "later statement"'s where the fields of the binding set as // Default::default() get reassigned, unless the reassignment refers to the original binding let mut first_assign = None; @@ -169,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find out if and which field was set by this `consecutive_statement` if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) { // interrupt and cancel lint if assign_rhs references the original binding - if contains_name(binding_name, assign_rhs, cx) { + if contains_name(binding_name, assign_rhs, cx) || init_ctxt != consecutive_statement.span.ctxt() { cancel_lint = true; break; } @@ -204,11 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for Default { .iter() .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name)); + let mut app = Applicability::Unspecified; let field_list = assigned_fields .into_iter() .map(|(field, rhs)| { // extract and store the assigned value for help message - let value_snippet = snippet_with_macro_callsite(cx, rhs.span, ".."); + let value_snippet = snippet_with_context(cx, rhs.span, init_ctxt, "..", &mut app).0; format!("{field}: {value_snippet}") }) .collect::<Vec<String>>() diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 8a5a28c6b3d..8f68f90a2a1 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { self_ty, .. }) = item.kind; - if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived); if !item.span.from_expansion(); if let Some(def_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::Default, def_id); diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index b8428d66a5d..f425dd5fb70 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -24,8 +24,8 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for deriving `Hash` but implementing `PartialEq` - /// explicitly or vice versa. + /// Lints against manual `PartialEq` implementations for types with a derived `Hash` + /// implementation. /// /// ### Why is this bad? /// The implementation of these traits must agree (for @@ -54,8 +54,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for deriving `Ord` but implementing `PartialOrd` - /// explicitly or vice versa. + /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord` + /// or `PartialOrd` implementation. /// /// ### Why is this bad? /// The implementation of these traits must agree (for @@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { }) = item.kind { let ty = cx.tcx.type_of(item.owner_id).subst_identity(); - let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived); check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived); diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 29bdc46b647..1e9e826631c 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -22,13 +22,13 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); - } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { + } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, sig.decl, @@ -47,13 +47,10 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); - } else if is_public - && !is_proc_macro(cx.sess(), attrs) - && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - { + } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { check_must_use_candidate( cx, sig.decl, @@ -73,12 +70,12 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); - if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) { + if attr.is_none() && is_public && !is_proc_macro(attrs) { check_must_use_candidate( cx, sig.decl, diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 9fb73a371b8..ed0bd58c770 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -9,7 +9,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; -use rustc_trait_selection::traits::{self, FulfillmentError}; +use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; declare_clippy_lint! { /// ### What it does @@ -79,8 +79,10 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let infcx = cx.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); - let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait); + ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); + let send_errors = ocx.select_all_or_error(); if !send_errors.is_empty() { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index 9cadaaa493e..725bd3d54bc 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; +use clippy_utils::sugg::Sugg; use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; +use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -72,21 +74,20 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } + let ctxt = expr.span.ctxt(); + if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind + && then_expr.span.ctxt() == ctxt && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome) && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) && !stmts_contains_early_return(then_block.stmts) { - let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); - let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { - format!("({cond_snip})") - } else { - cond_snip.into_owned() - }; - let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); + let mut app = Applicability::Unspecified; + let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string(); + let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() } else { diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index d1d2db27c6f..fe28c526be3 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -167,7 +167,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { Finite }, ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), - ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), + ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), ExprKind::Call(path, _) => { if let ExprKind::Path(ref qpath) = path.kind { cx.qpath_res(qpath, path.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs index ba51973f2f9..c01e3882d52 100644 --- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::*; +use rustc_hir::{Local, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 491732be208..c9210bf73f8 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -67,6 +67,7 @@ mod declared_lints; mod renamed_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` +mod allow_attributes; mod almost_complete_range; mod approx_const; mod as_conversions; @@ -179,6 +180,7 @@ mod manual_bits; mod manual_clamp; mod manual_is_ascii_check; mod manual_let_else; +mod manual_main_separator_str; mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; @@ -300,6 +302,7 @@ mod unit_types; mod unnamed_address; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; +mod unnecessary_struct_initialization; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; @@ -656,7 +659,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); store.register_late_pass(|_| Box::new(regex::Regex)); - store.register_late_pass(|_| Box::new(copies::CopyAndPaste)); + let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); + store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); store.register_late_pass(|_| Box::new(format::UselessFormat)); store.register_late_pass(|_| Box::new(swap::Swap)); @@ -933,6 +937,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage)); store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock)); store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped)); + store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); + store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); + store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index b1bc10802e1..f0a1b1dfe56 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -124,8 +124,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t #[allow(clippy::too_many_lines)] fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult { match expr.kind { - ExprKind::Box(e) - | ExprKind::Unary(_, e) + ExprKind::Unary(_, e) | ExprKind::Cast(e, _) | ExprKind::Type(e, _) | ExprKind::Field(e, _) diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 540656a2cd9..9d9341559ac 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -1,15 +1,17 @@ use super::SAME_ITEM_PUSH; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; +use rustc_span::SyntaxContext; use std::iter::Iterator; /// Detects for loop pushing the same item into a Vec @@ -20,9 +22,10 @@ pub(super) fn check<'tcx>( body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, ) { - fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext) { + let mut app = Applicability::Unspecified; + let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0; + let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0; span_lint_and_help( cx, @@ -43,7 +46,7 @@ pub(super) fn check<'tcx>( walk_expr(&mut same_item_push_visitor, body); if_chain! { if same_item_push_visitor.should_lint(); - if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push; + if let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push; let vec_ty = cx.typeck_results().expr_ty(vec); let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); if cx @@ -69,11 +72,11 @@ pub(super) fn check<'tcx>( then { match init.kind { // immutable bindings that are initialized with literal - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), // immutable bindings that are initialized with constant ExprKind::Path(ref path) => { if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) { - emit_lint(cx, vec, pushed_item); + emit_lint(cx, vec, pushed_item, ctxt); } } _ => {}, @@ -82,11 +85,11 @@ pub(super) fn check<'tcx>( } }, // constant - Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item), + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt), _ => {}, } }, - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), _ => {}, } } @@ -98,7 +101,7 @@ struct SameItemPushVisitor<'a, 'tcx> { non_deterministic_expr: bool, multiple_pushes: bool, // this field holds the last vec push operation visited, which should be the only push seen - vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>, + vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)>, cx: &'a LateContext<'tcx>, used_locals: FxHashSet<HirId>, } @@ -118,7 +121,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> { if_chain! { if !self.non_deterministic_expr; if !self.multiple_pushes; - if let Some((vec, _)) = self.vec_push; + if let Some((vec, _, _)) = self.vec_push; if let Some(hir_id) = path_to_local(vec); then { !self.used_locals.contains(&hir_id) @@ -173,7 +176,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { // Given some statement, determine if that statement is a push on a Vec. If it is, return // the Vec being pushed into and the item being pushed -fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { +fn get_vec_push<'tcx>( + cx: &LateContext<'tcx>, + stmt: &'tcx Stmt<'_>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> { if_chain! { // Extract method being called if let StmtKind::Semi(semi_stmt) = &stmt.kind; @@ -184,7 +190,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; then { - return Some((self_expr, pushed_item)) + return Some((self_expr, pushed_item, semi_stmt.span.ctxt())) } } None diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index f97c6bcb5d1..577bc1d661d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, - ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind, + ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - _: LocalDefId, + def_id: LocalDefId, ) { if_chain! { if let Some(header) = kind.header(); @@ -59,6 +59,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { if let ExprKind::Block(block, _) = body.value.kind; if block.stmts.is_empty(); if let Some(closure_body) = desugared_async_block(cx, block); + if let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = + cx.tcx.hir().get_by_def_id(def_id); then { let header_span = span.with_hi(ret_ty.span.hi()); @@ -69,15 +71,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { "this function can be simplified using the `async fn` syntax", |diag| { if_chain! { + if let Some(vis_snip) = snippet_opt(cx, *vis_span); if let Some(header_snip) = snippet_opt(cx, header_span); if let Some(ret_pos) = position_before_rarrow(&header_snip); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { + let header_snip = if vis_snip.is_empty() { + format!("async {}", &header_snip[..ret_pos]) + } else { + format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos]) + }; + let help = format!("make the function `async` and {ret_sugg}"); diag.span_suggestion( header_span, help, - format!("async {}{ret_snip}", &header_snip[..ret_pos]), + format!("{header_snip}{ret_snip}"), Applicability::MachineApplicable ); diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index f239736d38a..440362b96b4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -6,7 +6,8 @@ use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::MaybePath; use clippy_utils::{ - eq_expr_value, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt, + eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, + peel_blocks_with_stmt, }; use itertools::Itertools; use rustc_errors::Applicability; @@ -117,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { if !self.msrv.meets(msrvs::CLAMP) { return; } - if !expr.span.from_expansion() { + if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) { let suggestion = is_if_elseif_else_pattern(cx, expr) .or_else(|| is_max_min_pattern(cx, expr)) .or_else(|| is_call_max_min_pattern(cx, expr)) @@ -130,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { } fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { - if !self.msrv.meets(msrvs::CLAMP) { + if !self.msrv.meets(msrvs::CLAMP) || in_constant(cx, block.hir_id) { return; } for suggestion in is_two_if_pattern(cx, block) { diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs new file mode 100644 index 00000000000..c292bbe4e93 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs @@ -0,0 +1,74 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs}; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind, Mutability, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for references on `std::path::MAIN_SEPARATOR.to_string()` used + /// to build a `&str`. + /// + /// ### Why is this bad? + /// There exists a `std::path::MAIN_SEPARATOR_STR` which does not require + /// an extra memory allocation. + /// + /// ### Example + /// ```rust + /// let s: &str = &std::path::MAIN_SEPARATOR.to_string(); + /// ``` + /// Use instead: + /// ```rust + /// let s: &str = std::path::MAIN_SEPARATOR_STR; + /// ``` + #[clippy::version = "1.70.0"] + pub MANUAL_MAIN_SEPARATOR_STR, + complexity, + "`&std::path::MAIN_SEPARATOR.to_string()` can be replaced by `std::path::MAIN_SEPARATOR_STR`" +} + +pub struct ManualMainSeparatorStr { + msrv: Msrv, +} + +impl ManualMainSeparatorStr { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]); + +impl LateLintPass<'_> for ManualMainSeparatorStr { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && + let (target, _) = peel_hir_expr_refs(expr) && + is_trait_method(cx, target, sym::ToString) && + let ExprKind::MethodCall(path, receiver, &[], _) = target.kind && + path.ident.name == sym::to_string && + let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && + let Res::Def(DefKind::Const, receiver_def_id) = path.res && + match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) && + let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && + ty.is_str() + { + span_lint_and_sugg( + cx, + MANUAL_MAIN_SEPARATOR_STR, + expr.span, + "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", + "replace with", + "std::path::MAIN_SEPARATOR_STR".to_owned(), + Applicability::MachineApplicable, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs index 6447899f2b9..b94501bf0ad 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs @@ -32,14 +32,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); - let suggestion = if scrutinee.span.from_expansion() { - // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)` - sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..") - } - else { - sugg::Sugg::hir(cx, scrutinee, "..").maybe_par() - }; - + let mut app = Applicability::MachineApplicable; + let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, @@ -48,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: format!( "{suggestion}.unwrap_or({reindented_or_body})", ), - Applicability::MachineApplicable, + app, ); } } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs index 1c216e13570..df1e585f10b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs @@ -10,9 +10,9 @@ use rustc_middle::ty; use super::MATCH_BOOL; -pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { +pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { // Type of expression is `bool`. - if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool { + if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool { span_lint_and_then( cx, MATCH_BOOL, @@ -36,24 +36,26 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: }; if let Some((true_expr, false_expr)) = exprs { + let mut app = Applicability::HasPlaceholders; + let ctxt = expr.span.ctxt(); let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { (false, false) => Some(format!( "if {} {} else {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, "..", Some(expr.span)), - expr_block(cx, false_expr, None, "..", Some(expr.span)) + snippet(cx, scrutinee.span, "b"), + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )), (false, true) => Some(format!( "if {} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, "..", Some(expr.span)) + snippet(cx, scrutinee.span, "b"), + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) )), (true, false) => { - let test = Sugg::hir(cx, ex, ".."); + let test = Sugg::hir(cx, scrutinee, ".."); Some(format!( "if {} {}", !test, - expr_block(cx, false_expr, None, "..", Some(expr.span)) + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )) }, (true, true) => None, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs index 80f964ba1b7..aba4c85c59e 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs @@ -1,13 +1,14 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::Sugg; use core::iter::once; +use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use super::MATCH_REF_PATS; -pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>) +pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, scrutinee: &Expr<'_>, pats: I, expr: &Expr<'_>) where 'b: 'a, I: Clone + Iterator<Item = &'a Pat<'b>>, @@ -17,13 +18,28 @@ where } let (first_sugg, msg, title); - let span = ex.span.source_callsite(); - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind { - first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string())); + let ctxt = expr.span.ctxt(); + let mut app = Applicability::Unspecified; + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = scrutinee.kind { + if scrutinee.span.ctxt() != ctxt { + return; + } + first_sugg = once(( + scrutinee.span, + Sugg::hir_with_context(cx, inner, ctxt, "..", &mut app).to_string(), + )); msg = "try"; title = "you don't need to add `&` to both the expression and the patterns"; } else { - first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string())); + let Some(span) = walk_span_to_context(scrutinee.span, ctxt) else { + return; + }; + first_sugg = once(( + span, + Sugg::hir_with_context(cx, scrutinee, ctxt, "..", &mut app) + .deref() + .to_string(), + )); msg = "instead of prefixing all patterns with `&`, you can dereference the expression"; title = "you don't need to add `&` to all patterns"; } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs index 065a5c72621..89da7a55cbd 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::HirNode; -use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_with_applicability}; -use clippy_utils::sugg::Sugg; +use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_applicability}; use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -24,21 +23,30 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e let matched_vars = ex.span; let bind_names = arms[0].pat.span; let match_body = peel_blocks(arms[0].body); - let mut snippet_body = if match_body.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string() - } else { - snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string() - }; + let mut app = Applicability::MaybeIncorrect; + let mut snippet_body = snippet_block_with_context( + cx, + match_body.span, + arms[0].span.ctxt(), + "..", + Some(expr.span), + &mut app, + ) + .0 + .to_string(); // Do we need to add ';' to suggestion ? - if let ExprKind::Block(block, _) = match_body.kind { - // macro + expr_ty(body) == () - if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() { - snippet_body.push(';'); + if let Node::Stmt(stmt) = cx.tcx.hir().get_parent(expr.hir_id) + && let StmtKind::Expr(_) = stmt.kind + && match match_body.kind { + // We don't need to add a ; to blocks, unless that block is from a macro expansion + ExprKind::Block(block, _) => block.span.from_expansion(), + _ => true, } + { + snippet_body.push(';'); } - let mut applicability = Applicability::MaybeIncorrect; match arms[0].pat.kind { PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => { let (target_span, sugg) = match opt_parent_assign_span(cx, ex) { @@ -48,7 +56,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, Some(span), true, ); @@ -60,7 +68,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this assignment could be simplified", "consider removing the `match` expression", sugg, - applicability, + app, ); return; @@ -69,10 +77,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e span, format!( "let {} = {};\n{}let {} = {snippet_body};", - snippet_with_applicability(cx, bind_names, "..", &mut applicability), - snippet_with_applicability(cx, matched_vars, "..", &mut applicability), + snippet_with_applicability(cx, bind_names, "..", &mut app), + snippet_with_applicability(cx, matched_vars, "..", &mut app), " ".repeat(indent_of(cx, expr.span).unwrap_or(0)), - snippet_with_applicability(cx, pat_span, "..", &mut applicability) + snippet_with_applicability(cx, pat_span, "..", &mut app) ), ), None => { @@ -81,7 +89,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, None, true, ); @@ -96,7 +104,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this match could be written as a `let` statement", "consider using a `let` statement", sugg, - applicability, + app, ); }, PatKind::Wild => { @@ -106,7 +114,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, None, false, ); @@ -118,7 +126,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this match could be replaced by its scrutinee and body", "consider using the scrutinee and body instead", sugg, - applicability, + app, ); } else { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index df0ea7f5b86..7b609ff3df8 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,6 +1,6 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; @@ -150,22 +150,25 @@ fn find_sugg_for_if_let<'tcx>( // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ let expr_span = expr.span; + let ctxt = expr.span.ctxt(); // if/while let ... = ... { ... } - // ^^^ - let op_span = result_expr.span.source_callsite(); + // ^^^ + let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else { + return; + }; // if/while let ... = ... { ... } - // ^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(op_span.shrink_to_hi()); + // ^^^^^^^^^^^^^^^^^^^^^^ + let span = expr_span.until(res_span.shrink_to_hi()); - let app = if needs_drop { + let mut app = if needs_drop { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable }; - let sugg = Sugg::hir_with_macro_callsite(cx, result_expr, "_") + let sugg = Sugg::hir_with_context(cx, result_expr, ctxt, "_", &mut app) .maybe_par() .to_string(); diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index b33a2478172..04225beeb70 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -321,7 +321,6 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { self.has_significant_drop = true; } } - ExprKind::Box(..) | ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Unary(..) | diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 19b49c44d57..ad47c13896c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -67,8 +67,10 @@ fn report_single_pattern( els: Option<&Expr<'_>>, ) { let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH }; + let ctxt = expr.span.ctxt(); + let mut app = Applicability::HasPlaceholders; let els_str = els.map_or(String::new(), |els| { - format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span))) + format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); @@ -103,7 +105,7 @@ fn report_single_pattern( // PartialEq for different reference counts may not exist. "&".repeat(ref_count_diff), snippet(cx, arms[0].pat.span, ".."), - expr_block(cx, arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) } else { @@ -112,21 +114,13 @@ fn report_single_pattern( "if let {} = {} {}{els_str}", snippet(cx, arms[0].pat.span, ".."), snippet(cx, ex.span, ".."), - expr_block(cx, arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) } }; - span_lint_and_sugg( - cx, - lint, - expr.span, - msg, - "try this", - sugg, - Applicability::HasPlaceholders, - ); + span_lint_and_sugg(cx, lint, expr.span, msg, "try this", sugg, app); } fn check_opt_like<'a>( diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs index 8e1130cf8df..00853348840 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,6 +1,6 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -76,11 +76,8 @@ pub(crate) trait BindInsteadOfMap { if !contains_return(inner_expr); if let Some(msg) = Self::lint_msg(cx); then { - let some_inner_snip = if inner_expr.span.from_expansion() { - snippet_with_macro_callsite(cx, inner_expr.span, "_") - } else { - snippet(cx, inner_expr.span, "_") - }; + let mut app = Applicability::MachineApplicable; + let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0; let closure_args_snip = snippet(cx, closure_args_span, ".."); let option_snip = snippet(cx, recv.span, ".."); @@ -92,7 +89,7 @@ pub(crate) trait BindInsteadOfMap { &msg, "try this", note, - Applicability::MachineApplicable, + app, ); true } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs index 355f53532e2..5e8ad0861f3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -33,7 +33,9 @@ pub(super) fn check( return; }; - let snippet = snippet_with_macro_callsite(cx, receiver.span, ".."); + // Sometimes unnecessary ::<_> after Rc/Arc/Weak + let mut app = Applicability::Unspecified; + let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0; span_lint_and_sugg( cx, @@ -42,7 +44,7 @@ pub(super) fn check( "using `.clone()` on a ref-counted pointer", "try this", format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)), - Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak + app, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index 4460f38fcc1..7ce28ea93e0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{contains_return, is_trait_item, last_path_segment}; use if_chain::if_chain; @@ -9,7 +9,6 @@ use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; -use std::borrow::Cow; use super::OR_FUN_CALL; @@ -111,37 +110,24 @@ pub(super) fn check<'tcx>( if poss.contains(&name); then { + let ctxt = span.ctxt(); + let mut app = Applicability::HasPlaceholders; let sugg = { let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { (false, Some(fun_span)) => (fun_span, false), _ => (arg.span, true), }; - let format_span = |span: Span| { - let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, ".."); - let snip = if not_macro_argument_snippet == "vec![]" { - let macro_expanded_snipped = snippet(cx, snippet_span, ".."); - match macro_expanded_snipped.strip_prefix("$crate::vec::") { - Some(stripped) => Cow::Owned(stripped.to_owned()), - None => macro_expanded_snipped, - } - } else { - not_macro_argument_snippet - }; - - snip.to_string() - }; - - let snip = format_span(snippet_span); + let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0; let snip = if use_lambda { let l_arg = if fn_has_arguments { "_" } else { "" }; format!("|{l_arg}| {snip}") } else { - snip + snip.into_owned() }; if let Some(f) = second_arg { - let f = format_span(f.span); + let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0; format!("{snip}, {f}") } else { snip @@ -155,7 +141,7 @@ pub(super) fn check<'tcx>( &format!("use of `{name}` followed by a function call"), "try this", format!("{name}_{suffix}({sugg})"), - Applicability::HasPlaceholders, + app, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index 5201da52bbf..67618f7038a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -33,10 +33,6 @@ struct SortByKeyDetection { /// contains a and the other replaces it with b) fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { match (&a_expr.kind, &b_expr.kind) { - // Two boxes with mirrored contents - (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => { - mirrored_exprs(left_expr, a_ident, right_expr, b_ident) - }, // Two arrays with mirrored contents (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 0705029a613..3752b9a946f 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_context}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -181,20 +181,17 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; then { - // use the macro callsite when the init span (but not the whole local span) - // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` - let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, init, "..") - } else { - Sugg::hir(cx, init, "..") - }; + let ctxt = local.span.ctxt(); + let mut app = Applicability::MachineApplicable; + let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app); let (mutopt, initref) = if mutabl == Mutability::Mut { ("mut ", sugg_init.mut_addr()) } else { ("", sugg_init.addr()) }; let tyopt = if let Some(ty) = local.ty { - format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, "..")) + let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0; + format!(": &{mutopt}{ty_snip}") } else { String::new() }; @@ -212,7 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { "let {name}{tyopt} = {initref};", name=snippet(cx, name.span, ".."), ), - Applicability::MachineApplicable, + app, ); } ); diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 8aa814b7405..309f67521a3 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_interior_mut_ty; use clippy_utils::{def_path_def_ids, trait_ref_of_method}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty}; +use rustc_middle::query::Key; +use rustc_middle::ty::{Adt, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -153,53 +154,18 @@ impl MutableKeyType { let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] .iter() .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did())); - if is_keyed_type && self.is_interior_mutable_type(cx, substs.type_at(0)) { - span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); + if !is_keyed_type { + return; } - } - } - /// Determines if a type contains interior mutability which would affect its implementation of - /// [`Hash`] or [`Ord`]. - fn is_interior_mutable_type<'tcx>(&self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match *ty.kind() { - Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty), - Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty), - Array(inner_ty, size) => { - size.try_eval_target_usize(cx.tcx, cx.param_env) - .map_or(true, |u| u != 0) - && self.is_interior_mutable_type(cx, inner_ty) - }, - Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)), - Adt(def, substs) => { - // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to - // that of their type parameters. Note: we don't include `HashSet` and `HashMap` - // because they have no impl for `Hash` or `Ord`. - let def_id = def.did(); - let is_std_collection = [ - sym::Option, - sym::Result, - sym::LinkedList, - sym::Vec, - sym::VecDeque, - sym::BTreeMap, - sym::BTreeSet, - sym::Rc, - sym::Arc, - ] - .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id)); - let is_box = Some(def_id) == cx.tcx.lang_items().owned_box(); - if is_std_collection || is_box || self.ignore_mut_def_ids.contains(&def_id) { - // The type is mutable if any of its type parameters are - substs.types().any(|ty| self.is_interior_mutable_type(cx, ty)) - } else { - !ty.has_escaping_bound_vars() - && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() - && !ty.is_freeze(cx.tcx, cx.param_env) - } - }, - _ => false, + let subst_ty = substs.type_at(0); + // Determines if a type contains interior mutability which would affect its implementation of + // [`Hash`] or [`Ord`]. + if is_interior_mut_ty(cx, subst_ty) + && !matches!(subst_ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id)) + { + span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index a4eec95b371..c87059bf61d 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -340,18 +340,11 @@ fn suggest_bool_comparison<'a, 'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, expr: &Expr<'_>, - mut applicability: Applicability, + mut app: Applicability, message: &str, conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, ) { - let hint = if expr.span.from_expansion() { - if applicability != Applicability::Unspecified { - applicability = Applicability::MaybeIncorrect; - } - Sugg::hir_with_macro_callsite(cx, expr, "..") - } else { - Sugg::hir_with_applicability(cx, expr, "..", &mut applicability) - }; + let hint = Sugg::hir_with_context(cx, expr, e.span.ctxt(), "..", &mut app); span_lint_and_sugg( cx, BOOL_COMPARISON, @@ -359,7 +352,7 @@ fn suggest_bool_comparison<'a, 'tcx>( message, "try simplifying it as shown", conv_hint(hint).to_string(), - applicability, + app, ); } diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 79c1ae4861e..e3712190e67 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -127,8 +127,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ExprKind::Type(inner, _) | ExprKind::Unary(_, inner) | ExprKind::Field(inner, _) - | ExprKind::AddrOf(_, _, inner) - | ExprKind::Box(inner) => has_no_effect(cx, inner), + | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner), ExprKind::Struct(_, fields, ref base) => { !has_drop(cx, cx.typeck_results().expr_ty(expr)) && fields.iter().all(|field| has_no_effect(cx, field.expr)) @@ -234,8 +233,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec | ExprKind::Type(inner, _) | ExprKind::Unary(_, inner) | ExprKind::Field(inner, _) - | ExprKind::AddrOf(_, _, inner) - | ExprKind::Box(inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), + | ExprKind::AddrOf(_, _, inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), ExprKind::Struct(_, fields, ref base) => { if has_drop(cx, cx.typeck_results().expr_ty(expr)) { None diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index bc64ccb295c..8fd9ae351a0 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -1,9 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi; declare_clippy_lint! { @@ -38,25 +39,28 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Fn(fn_sig, _, _) = &item.kind { let attrs = cx.tcx.hir().attrs(item.hir_id()); - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut applicability); + let mut app = Applicability::MaybeIncorrect; + let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app); for attr in attrs { if let Some(ident) = attr.ident() && ident.name == rustc_span::sym::no_mangle && fn_sig.header.abi == Abi::Rust - && !snippet.contains("extern") { + && let Some((fn_attrs, _)) = snippet.split_once("fn") + && !fn_attrs.contains("extern") + { + let sugg_span = fn_sig.span + .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) + .shrink_to_lo(); - let suggestion = snippet.split_once("fn") - .map_or(String::new(), |(first, second)| format!(r#"{first}extern "C" fn{second}"#)); - - span_lint_and_sugg( + span_lint_and_then( cx, NO_MANGLE_WITH_RUST_ABI, fn_sig.span, - "attribute #[no_mangle] set on a Rust ABI function", - "try", - suggestion, - applicability + "`#[no_mangle]` set on a function with the default (`Rust`) ABI", + |diag| { + diag.span_suggestion(sugg_span, "set an ABI", "extern \"C\" ", app) + .span_suggestion(sugg_span, "or explicitly set the default", "extern \"Rust\" ", app); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index c5ea09590d3..bbbcda069c5 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -12,6 +12,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::SyntaxContext; declare_clippy_lint! { /// ### What it does @@ -95,10 +96,10 @@ struct OptionOccurrence { none_expr: String, } -fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String { +fn format_option_in_sugg(cond_sugg: Sugg<'_>, as_ref: bool, as_mut: bool) -> String { format!( "{}{}", - Sugg::hir_with_macro_callsite(cx, cond_expr, "..").maybe_par(), + cond_sugg.maybe_par(), if as_mut { ".as_mut()" } else if as_ref { @@ -111,6 +112,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo fn try_get_option_occurrence<'tcx>( cx: &LateContext<'tcx>, + ctxt: SyntaxContext, pat: &Pat<'tcx>, expr: &Expr<'_>, if_then: &'tcx Expr<'_>, @@ -160,11 +162,23 @@ fn try_get_option_occurrence<'tcx>( } } + let mut app = Applicability::Unspecified; return Some(OptionOccurrence { - option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), + option: format_option_in_sugg( + Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app), + as_ref, + as_mut, + ), method_sugg: method_sugg.to_string(), - some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")), - none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")), + some_expr: format!( + "|{capture_mut}{capture_name}| {}", + Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app), + ), + none_expr: format!( + "{}{}", + if method_sugg == "map_or" { "" } else { "|| " }, + Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), + ), }); } } @@ -194,7 +208,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> }) = higher::IfLet::hir(cx, expr) { if !is_else_clause(cx.tcx, expr) { - return try_get_option_occurrence(cx, let_pat, let_expr, if_then, if_else); + return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else); } } None @@ -203,7 +217,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurrence> { if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) { - return try_get_option_occurrence(cx, let_pat, ex, if_then, if_else); + return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else); } } None diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index 5aa3c6f2f93..a8c4823fe53 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if_chain! { if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind; - if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived); if let Some(eq_trait) = cx.tcx.lang_items().eq_trait(); if trait_ref.path.res.def_id() == eq_trait; then { diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 27ad4308637..2d30e77d55d 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -1,5 +1,5 @@ use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet}; -use rustc_ast::ast::*; +use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::Visitor as AstVisitor; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.69.0"] pub REDUNDANT_ASYNC_BLOCK, - complexity, + nursery, "`async { future.await }` can be replaced by `future`" } declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]); @@ -48,6 +48,11 @@ impl EarlyLintPass for RedundantAsyncBlock { !future.span.from_expansion() && !await_in_expr(future) { + if captures_value(last) { + // If the async block captures variables then there is no equivalence. + return; + } + span_lint_and_sugg( cx, REDUNDANT_ASYNC_BLOCK, @@ -82,3 +87,33 @@ impl<'ast> AstVisitor<'ast> for AwaitDetector { } } } + +/// Check whether an expression may have captured a local variable. +/// This is done by looking for paths with only one segment, except as +/// a prefix of `.await` since this would be captured by value. +/// +/// This function will sometimes return `true` even tough there are no +/// captures happening: at the AST level, it is impossible to +/// dinstinguish a function call from a call to a closure which comes +/// from the local environment. +fn captures_value(expr: &Expr) -> bool { + let mut detector = CaptureDetector::default(); + detector.visit_expr(expr); + detector.capture_found +} + +#[derive(Default)] +struct CaptureDetector { + capture_found: bool, +} + +impl<'ast> AstVisitor<'ast> for CaptureDetector { + fn visit_expr(&mut self, ex: &'ast Expr) { + match (&ex.kind, self.capture_found) { + (ExprKind::Await(fut), _) if matches!(fut.kind, ExprKind::Path(..)) => (), + (ExprKind::Path(_, path), _) if path.segments.len() == 1 => self.capture_found = true, + (_, false) => rustc_ast::visit::walk_expr(self, ex), + _ => (), + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index 66638eed998..355f907e257 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,6 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::sugg; +use clippy_utils::source::snippet_with_context; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; @@ -44,7 +43,8 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); - if let snippet = snippet_with_macro_callsite(cx, expr.span, "}"); + let mut app = Applicability::MaybeIncorrect; + if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0; if !snippet.ends_with('}') && !snippet.ends_with(';'); if cx.sess().source_map().is_multiline(block.span); then { @@ -52,17 +52,14 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { if let ExprKind::DropTemps(..) = &expr.kind { return; } - - let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, ".."); - let suggestion = format!("{sugg};"); span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, expr.span.source_callsite(), "consider adding a `;` to the last statement for consistent formatting", "add a `;` here", - suggestion, - Applicability::MaybeIncorrect, + format!("{snippet};"), + app, ); } } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 87f966ced0d..ae7d19624ba 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -213,8 +213,7 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_ } loop { expr = match expr.kind { - ExprKind::Box(e) - | ExprKind::AddrOf(_, _, e) + ExprKind::AddrOf(_, _, e) | ExprKind::Block( &Block { stmts: [], diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index e2d90edec5a..869358fb1ba 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -1,9 +1,9 @@ -use crate::FxHashSet; use clippy_utils::{ diagnostics::span_lint_and_then, get_attr, source::{indent_of, snippet}, }; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{ self as hir, @@ -58,6 +58,7 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); pub struct SignificantDropTightening<'tcx> { /// Auxiliary structure used to avoid having to verify the same type multiple times. seen_types: FxHashSet<Ty<'tcx>>, + type_cache: FxHashMap<Ty<'tcx>, bool>, } impl<'tcx> SignificantDropTightening<'tcx> { @@ -118,7 +119,7 @@ impl<'tcx> SignificantDropTightening<'tcx> { stmt: &hir::Stmt<'_>, cb: impl Fn(&mut SigDropAuxParams), ) { - let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types); + let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types, &mut self.type_cache); sig_drop_finder.visit_expr(expr); if sig_drop_finder.has_sig_drop { cb(sdap); @@ -296,15 +297,24 @@ impl Default for SigDropAuxParams { struct SigDropChecker<'cx, 'sdt, 'tcx> { cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>, + type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>, } impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { - pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self { + pub(crate) fn new( + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet<Ty<'tcx>>, + type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>, + ) -> Self { seen_types.clear(); - Self { cx, seen_types } + Self { + cx, + seen_types, + type_cache, + } } - pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + pub(crate) fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool { if let Some(adt) = ty.ty_adt_def() { let mut iter = get_attr( self.cx.sess(), @@ -340,6 +350,16 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { } } + pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + // The borrow checker prevents us from using something fancier like or_insert_with. + if let Some(ty) = self.type_cache.get(&ty) { + return *ty; + } + let value = self.has_sig_drop_attr_uncached(ty); + self.type_cache.insert(ty, value); + value + } + fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool { !self.seen_types.insert(ty) } @@ -353,11 +373,15 @@ struct SigDropFinder<'cx, 'sdt, 'tcx> { } impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> { - fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self { + fn new( + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet<Ty<'tcx>>, + type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>, + ) -> Self { Self { cx, has_sig_drop: false, - sig_drop_checker: SigDropChecker::new(cx, seen_types), + sig_drop_checker: SigDropChecker::new(cx, seen_types, type_cache), } } } @@ -380,7 +404,6 @@ impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> { | hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | hir::ExprKind::Binary(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Call(..) | hir::ExprKind::Field(..) | hir::ExprKind::If(..) diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 1aeac724ab1..f7eef03d1d4 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -6,7 +6,8 @@ use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core} use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; @@ -188,8 +189,10 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { if let Some((lhs0, rhs0)) = parse(first) && let Some((lhs1, rhs1)) = parse(second) && first.span.eq_ctxt(second.span) + && !in_external_macro(cx.sess(), first.span) && is_same(cx, lhs0, rhs1) && is_same(cx, lhs1, rhs0) + && !is_same(cx, lhs1, rhs1) // Ignore a = b; a = a (#10421) && let Some(lhs_sugg) = match &lhs0 { ExprOrIdent::Expr(expr) => Sugg::hir_opt(cx, expr), ExprOrIdent::Ident(ident) => Some(Sugg::NonParen(ident.as_str().into())), @@ -257,8 +260,8 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< /// Implementation of the xor case for `MANUAL_SWAP` lint. fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { for [s1, s2, s3] in block.stmts.array_windows::<3>() { + let ctxt = s1.span.ctxt(); if_chain! { - let ctxt = s1.span.ctxt(); if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt); if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt); if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt); diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index 3430b6e3734..cc7c2b039f2 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_node; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -52,12 +52,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { "this let-binding has unit value", |diag| { if let Some(expr) = &local.init { - let snip = snippet_with_macro_callsite(cx, expr.span, "()"); + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; diag.span_suggestion( local.span, "omit the `let` binding", format!("{snip};"), - Applicability::MachineApplicable, // snippet + app, ); } }, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs new file mode 100644 index 00000000000..af0b4b1592f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs @@ -0,0 +1,84 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_expr, path_to_local, source::snippet, ty::is_copy}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for initialization of a `struct` by copying a base without setting + /// any field. + /// + /// ### Why is this bad? + /// Readibility suffers from unnecessary struct building. + /// + /// ### Example + /// ```rust + /// struct S { s: String } + /// + /// let a = S { s: String::from("Hello, world!") }; + /// let b = S { ..a }; + /// ``` + /// Use instead: + /// ```rust + /// struct S { s: String } + /// + /// let a = S { s: String::from("Hello, world!") }; + /// let b = a; + /// ``` + #[clippy::version = "1.70.0"] + pub UNNECESSARY_STRUCT_INITIALIZATION, + complexity, + "struct built from a base that can be written mode concisely" +} +declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); + +impl LateLintPass<'_> for UnnecessaryStruct { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Struct(_, &[], Some(base)) = expr.kind { + if let Some(parent) = get_parent_expr(cx, expr) && + let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) && + parent_ty.is_any_ptr() + { + if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() { + // When the type implements `Copy`, a reference to the new struct works on the + // copy. Using the original would borrow it. + return; + } + + if parent_ty.is_mutable_ptr() && !is_mutable(cx, base) { + // The original can be used in a mutable reference context only if it is mutable. + return; + } + } + + // TODO: do not propose to replace *XX if XX is not Copy + if let ExprKind::Unary(UnOp::Deref, target) = base.kind && + matches!(target.kind, ExprKind::Path(..)) && + !is_copy(cx, cx.typeck_results().expr_ty(expr)) + { + // `*base` cannot be used instead of the struct in the general case if it is not Copy. + return; + } + + span_lint_and_sugg( + cx, + UNNECESSARY_STRUCT_INITIALIZATION, + expr.span, + "unnecessary struct building", + "replace with", + snippet(cx, base.span, "..").into_owned(), + rustc_errors::Applicability::MachineApplicable, + ); + } + } +} + +fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(hir_id) = path_to_local(expr) && + let Node::Pat(pat) = cx.tcx.hir().get(hir_id) + { + matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..)) + } else { + true + } +} diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index fede625f72a..ddbe6b2c790 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths}; @@ -68,15 +68,16 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet_with_macro_callsite(cx, recv.span, "<expr>").to_string(); + let mut app = Applicability::MachineApplicable; + let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "<expr>", &mut app).0; span_lint_and_sugg( cx, USELESS_CONVERSION, e.span, &format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", - sugg, - Applicability::MachineApplicable, // snippet + sugg.into_owned(), + app, ); } } @@ -165,7 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if same_type_and_consts(a, b); then { - let sugg = Sugg::hir_with_macro_callsite(cx, arg, "<expr>").maybe_par(); + let mut app = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_par(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( @@ -175,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { &format!("useless conversion to the same type: `{b}`"), &sugg_msg, sugg.to_string(), - Applicability::MachineApplicable, // snippet + app, ); } } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index f31c3fdb095..bc4adf1596d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -395,11 +395,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } self.expr(field!(let_expr.init)); }, - ExprKind::Box(inner) => { - bind!(self, inner); - kind!("Box({inner})"); - self.expr(inner); - }, ExprKind::Array(elements) => { bind!(self, elements); kind!("Array({elements})"); diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 1c7f3e96db8..8ba252425a3 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -437,7 +437,7 @@ define_Conf! { /// /// The maximum size of the `Err`-variant in a `Result` returned from a function (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY_TYPE. + /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND. /// /// A list of paths to types that should be treated like `Arc`, i.e. ignored but /// for the generic parameters for determining interior mutability diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index e105452e1c5..36f910c983f 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -158,12 +158,10 @@ impl LateLintPass<'_> for WildcardImports { let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(false); let imports_string = if imports.len() == 1 { imports.pop().unwrap() + } else if braced_glob { + imports.join(", ") } else { - if braced_glob { - imports.join(", ") - } else { - format!("{{{}}}", imports.join(", ")) - } + format!("{{{}}}", imports.join(", ")) }; let sugg = if braced_glob { diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 7987a233bdc..b4ad42a5027 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -145,8 +145,8 @@ pub fn get_unique_attr<'a>( /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise -pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| sess.is_proc_macro_attr(attr)) +pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { + attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr) } /// Return true if the attributes contain `#[doc(hidden)]` diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 43f0df145f0..d3a6929f67e 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -112,7 +112,6 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { /// Get the search patterns to use for the given expression fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { match e.kind { - ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1), ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index ee2f816f181..28c85717061 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -199,11 +199,9 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, // Memory allocation, custom operator, loop, or call to an unknown function - ExprKind::Box(_) - | ExprKind::Unary(..) - | ExprKind::Binary(..) - | ExprKind::Loop(..) - | ExprKind::Call(..) => self.eagerness = Lazy, + ExprKind::Unary(..) | ExprKind::Binary(..) | ExprKind::Loop(..) | ExprKind::Call(..) => { + self.eagerness = Lazy; + }, ExprKind::ConstBlock(_) | ExprKind::Array(_) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 0603755f8a9..3a6d23ca5c1 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -249,7 +249,6 @@ impl HirEqInterExpr<'_, '_, '_> { both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) && both(le, re, |l, r| self.eq_expr(l, r)) }, - (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r), (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => { self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) }, @@ -628,7 +627,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(j); } }, - ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { + ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { self.hash_expr(e); }, ExprKind::Call(fun, args) => { diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index e135bd9feee..c0e32068eca 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -533,6 +533,14 @@ struct FormatArgsValues<'tcx> { } impl<'tcx> FormatArgsValues<'tcx> { + fn new_empty(format_string_span: SpanData) -> Self { + Self { + value_args: Vec::new(), + pos_to_value_index: Vec::new(), + format_string_span, + } + } + fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { let mut pos_to_value_index = Vec::new(); let mut value_args = Vec::new(); @@ -997,12 +1005,13 @@ impl<'tcx> FormatArgsExpn<'tcx> { .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?; let newline = macro_name == sym::format_args_nl; + // ::core::fmt::Arguments::new_const(pieces) // ::core::fmt::Arguments::new_v1(pieces, args) // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) - if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind + if let ExprKind::Call(callee, [pieces, rest @ ..]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind - && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted") + && matches!(seg.ident.as_str(), "new_const" | "new_v1" | "new_v1_formatted") { let format_string = FormatString::new(cx, pieces)?; @@ -1026,7 +1035,7 @@ impl<'tcx> FormatArgsExpn<'tcx> { return None; } - let positions = if let Some(fmt_arg) = rest.first() { + let positions = if let Some(fmt_arg) = rest.get(1) { // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse // them. @@ -1042,7 +1051,11 @@ impl<'tcx> FormatArgsExpn<'tcx> { })) }; - let values = FormatArgsValues::new(args, format_string.span.data()); + let values = if let Some(args) = rest.first() { + FormatArgsValues::new(args, format_string.span.data()) + } else { + FormatArgsValues::new_empty(format_string.span.data()) + }; let args = izip!(positions, parsed_args, parser.arg_places) .map(|(position, parsed_arg, arg_span)| { diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index dbf9f3b621d..e05de2dc99c 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -19,6 +19,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 4aae0f7284e..c919575bfe9 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -67,6 +67,7 @@ pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; +pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"]; pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"]; diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 24403e8b6f3..d66640ba0b7 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -37,7 +37,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"), + ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"), ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"), ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"), ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"), @@ -176,6 +176,10 @@ fn check_rvalue<'tcx>( // FIXME(dyn-star) unimplemented!() }, + Rvalue::Cast(CastKind::Transmute, _, _) => Err(( + span, + "transmute can attempt to turn pointers into integers, so is unstable in const fn".into(), + )), // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index cd5dcfdaca3..62fa37660fa 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -12,24 +12,21 @@ use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. -/// Also takes an `Option<String>` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>( +pub fn expr_block<T: LintContext>( cx: &T, expr: &Expr<'_>, - option: Option<String>, - default: &'a str, + outer: SyntaxContext, + default: &str, indent_relative_to: Option<Span>, -) -> Cow<'a, str> { - let code = snippet_block(cx, expr.span, default, indent_relative_to); - let string = option.unwrap_or_default(); - if expr.span.from_expansion() { - Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) + app: &mut Applicability, +) -> String { + let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app); + if from_macro { + format!("{{ {code} }}") } else if let ExprKind::Block(_, _) = expr.kind { - Cow::Owned(format!("{code}{string}")) - } else if string.is_empty() { - Cow::Owned(format!("{{ {code} }}")) + format!("{code}") } else { - Cow::Owned(format!("{{\n{code};\n{string}\n}}")) + format!("{{ {code} }}") } } @@ -229,12 +226,6 @@ fn snippet_with_applicability_sess<'a>( ) } -/// Same as `snippet`, but should only be used when it's clear that the input span is -/// not a macro argument. -pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - snippet(cx, span.source_callsite(), default) -} - /// Converts a span to a code snippet. Returns `None` if not available. pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option<String> { snippet_opt_sess(cx.sess(), span) @@ -303,6 +294,19 @@ pub fn snippet_block_with_applicability<'a>( reindent_multiline(snip, true, indent) } +pub fn snippet_block_with_context<'a>( + cx: &impl LintContext, + span: Span, + outer: SyntaxContext, + default: &'a str, + indent_relative_to: Option<Span>, + app: &mut Applicability, +) -> (Cow<'a, str>, bool) { + let (snip, from_macro) = snippet_with_context(cx, span, outer, default, app); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); + (reindent_multiline(snip, true, indent), from_macro) +} + /// Same as `snippet_with_applicability`, but first walks the span up to the given context. This /// will result in the macro call, rather then the expansion, if the span is from a child context. /// If the span is not from a child context, it will be used directly instead. diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 85bf28b708b..a5a4a921d94 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -1,9 +1,7 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::source::{ - snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite, -}; +use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_context}; use crate::ty::expr_sig; use crate::{get_parent_expr_for_hir, higher}; use rustc_ast::util::parser::AssocOp; @@ -89,12 +87,6 @@ impl<'a> Sugg<'a> { }) } - /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro. - pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self { - let get_snippet = |span| snippet_with_macro_callsite(cx, span, default); - Self::hir_from_snippet(expr, get_snippet) - } - /// Same as `hir`, but first walks the span up to the given context. This will result in the /// macro call, rather then the expansion, if the span is from a child context. If the span is /// not from a child context, it will be used directly instead. @@ -133,7 +125,6 @@ impl<'a> Sugg<'a> { match expr.kind { hir::ExprKind::AddrOf(..) - | hir::ExprKind::Box(..) | hir::ExprKind::If(..) | hir::ExprKind::Let(..) | hir::ExprKind::Closure { .. } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index e0ea3952785..0b47234647f 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -16,9 +16,9 @@ use rustc_infer::infer::{ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind, - Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - UintTy, VariantDef, VariantDiscr, + self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, + Predicate, PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::Ident; @@ -538,13 +538,12 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { } /// Checks if a given type looks safe to be uninitialized. -pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match *ty.kind() { - ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), - ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), - ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()), - _ => false, - } +pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + cx.tcx + .check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty))) + // For types containing generic parameters we cannot get a layout to check. + // Therefore, we are conservative and assume that they don't allow uninit. + .unwrap_or(false) } /// Gets an iterator over all predicates which apply to the given item. @@ -1121,3 +1120,47 @@ pub fn make_normalized_projection<'tcx>( } helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?) } + +/// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`] +/// etc. +pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match *ty.kind() { + ty::Ref(_, inner_ty, mutbl) => mutbl == Mutability::Mut || is_interior_mut_ty(cx, inner_ty), + ty::Slice(inner_ty) => is_interior_mut_ty(cx, inner_ty), + ty::Array(inner_ty, size) => { + size.try_eval_target_usize(cx.tcx, cx.param_env) + .map_or(true, |u| u != 0) + && is_interior_mut_ty(cx, inner_ty) + }, + ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)), + ty::Adt(def, substs) => { + // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to + // that of their type parameters. Note: we don't include `HashSet` and `HashMap` + // because they have no impl for `Hash` or `Ord`. + let def_id = def.did(); + let is_std_collection = [ + sym::Option, + sym::Result, + sym::LinkedList, + sym::Vec, + sym::VecDeque, + sym::BTreeMap, + sym::BTreeSet, + sym::Rc, + sym::Arc, + ] + .iter() + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id)); + let is_box = Some(def_id) == cx.tcx.lang_items().owned_box(); + if is_std_collection || is_box { + // The type is mutable if any of its type parameters are + substs.types().any(|ty| is_interior_mut_ty(cx, ty)) + } else { + !ty.has_escaping_bound_vars() + && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() + && !ty.is_freeze(cx.tcx, cx.param_env) + } + }, + _ => false, + } +} diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index d27a20bd4df..1dc19bac984 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -599,10 +599,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Let(&Let { init: e, .. }) => { helper(typeck, false, e, f)?; }, - ExprKind::Block(&Block { expr: Some(e), .. }, _) - | ExprKind::Box(e) - | ExprKind::Cast(e, _) - | ExprKind::Unary(_, e) => { + ExprKind::Block(&Block { expr: Some(e), .. }, _) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => { helper(typeck, true, e, f)?; }, ExprKind::Call(callee, args) => { diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index d788c6359d7..0b2458ea007 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-03-10" +channel = "nightly-2023-03-24" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs index 9643c2c9707..3a5d478fa31 100644 --- a/src/tools/clippy/tests/dogfood.rs +++ b/src/tools/clippy/tests/dogfood.rs @@ -37,10 +37,10 @@ fn dogfood_clippy() { } assert!( - !failed_packages.is_empty(), + failed_packages.is_empty(), "Dogfood failed for packages `{}`", failed_packages.iter().format(", "), - ) + ); } #[test] diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr index 7ed0ef0274f..b4619e980f3 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr @@ -9,3 +9,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo +thread panicked while panicking. aborting. diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/clippy.toml b/src/tools/clippy/tests/ui-toml/ifs_same_cond/clippy.toml new file mode 100644 index 00000000000..90a36ecd920 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/clippy.toml @@ -0,0 +1 @@ +ignore-interior-mutability = ["std::cell::Cell"] diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs new file mode 100644 index 00000000000..d623ac7e020 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs @@ -0,0 +1,18 @@ +#![warn(clippy::ifs_same_cond)] +#![allow(clippy::if_same_then_else, clippy::comparison_chain)] + +fn main() {} + +fn issue10272() { + use std::cell::Cell; + + // Because the `ignore-interior-mutability` configuration + // is set to ignore for `std::cell::Cell`, the following `get()` calls + // should trigger warning + let x = Cell::new(true); + if x.get() { + } else if !x.take() { + } else if x.get() { + } else { + } +} diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr new file mode 100644 index 00000000000..2841f62bc94 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr @@ -0,0 +1,15 @@ +error: this `if` has the same condition as a previous `if` + --> $DIR/ifs_same_cond.rs:15:15 + | +LL | } else if x.get() { + | ^^^^^^^ + | +note: same as this + --> $DIR/ifs_same_cond.rs:13:8 + | +LL | if x.get() { + | ^^^^^^^ + = note: `-D clippy::ifs-same-cond` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/allow_attributes.fixed b/src/tools/clippy/tests/ui/allow_attributes.fixed new file mode 100644 index 00000000000..b8dd0619e6d --- /dev/null +++ b/src/tools/clippy/tests/ui/allow_attributes.fixed @@ -0,0 +1,25 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::allow_attributes)] +#![feature(lint_reasons)] + +fn main() {} + +// Using clippy::needless_borrow just as a placeholder, it isn't relevant. + +// Should lint +#[expect(dead_code)] +struct T1; + +struct T2; // Should not lint +#[deny(clippy::needless_borrow)] // Should not lint +struct T3; +#[warn(clippy::needless_borrow)] // Should not lint +struct T4; +// `panic = "unwind"` should always be true +#[cfg_attr(panic = "unwind", expect(dead_code))] +struct CfgT; + +fn ignore_inner_attr() { + #![allow(unused)] // Should not lint +} diff --git a/src/tools/clippy/tests/ui/allow_attributes.rs b/src/tools/clippy/tests/ui/allow_attributes.rs new file mode 100644 index 00000000000..295f560906a --- /dev/null +++ b/src/tools/clippy/tests/ui/allow_attributes.rs @@ -0,0 +1,25 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::allow_attributes)] +#![feature(lint_reasons)] + +fn main() {} + +// Using clippy::needless_borrow just as a placeholder, it isn't relevant. + +// Should lint +#[allow(dead_code)] +struct T1; + +struct T2; // Should not lint +#[deny(clippy::needless_borrow)] // Should not lint +struct T3; +#[warn(clippy::needless_borrow)] // Should not lint +struct T4; +// `panic = "unwind"` should always be true +#[cfg_attr(panic = "unwind", allow(dead_code))] +struct CfgT; + +fn ignore_inner_attr() { + #![allow(unused)] // Should not lint +} diff --git a/src/tools/clippy/tests/ui/allow_attributes.stderr b/src/tools/clippy/tests/ui/allow_attributes.stderr new file mode 100644 index 00000000000..681837e9ed7 --- /dev/null +++ b/src/tools/clippy/tests/ui/allow_attributes.stderr @@ -0,0 +1,16 @@ +error: #[allow] attribute found + --> $DIR/allow_attributes.rs:11:3 + | +LL | #[allow(dead_code)] + | ^^^^^ help: replace it with: `expect` + | + = note: `-D clippy::allow-attributes` implied by `-D warnings` + +error: #[allow] attribute found + --> $DIR/allow_attributes.rs:20:30 + | +LL | #[cfg_attr(panic = "unwind", allow(dead_code))] + | ^^^^^ help: replace it with: `expect` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/almost_complete_range.fixed b/src/tools/clippy/tests/ui/almost_complete_range.fixed index 6046addf719..a4bf7fe18d5 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.fixed +++ b/src/tools/clippy/tests/ui/almost_complete_range.fixed @@ -1,6 +1,6 @@ // run-rustfix // edition:2018 -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] @@ -9,33 +9,10 @@ #![allow(clippy::needless_parens_on_range_literals)] #![allow(clippy::double_parens)] -#[macro_use] -extern crate macro_rules; - -macro_rules! a { - () => { - 'a' - }; -} -macro_rules! A { - () => { - 'A' - }; -} -macro_rules! zero { - () => { - '0' - }; -} - -macro_rules! b { - () => { - let _ = 'a'..='z'; - let _ = 'A'..='Z'; - let _ = '0'..='9'; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { #[rustfmt::skip] { @@ -56,9 +33,9 @@ fn main() { let _ = b'B'..b'Z'; let _ = b'1'..b'9'; - let _ = a!()..='z'; - let _ = A!()..='Z'; - let _ = zero!()..='9'; + let _ = inline!('a')..='z'; + let _ = inline!('A')..='Z'; + let _ = inline!('0')..='9'; let _ = match 0u8 { b'a'..=b'z' if true => 1, @@ -80,8 +57,16 @@ fn main() { _ => 7, }; - almost_complete_range!(); - b!(); + external!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); + inline!( + let _ = 'a'..='z'; + let _ = 'A'..='Z'; + let _ = '0'..='9'; + ); } #[clippy::msrv = "1.25"] diff --git a/src/tools/clippy/tests/ui/almost_complete_range.rs b/src/tools/clippy/tests/ui/almost_complete_range.rs index ae7e07ab872..8237c3a1361 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.rs +++ b/src/tools/clippy/tests/ui/almost_complete_range.rs @@ -1,6 +1,6 @@ // run-rustfix // edition:2018 -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] @@ -9,33 +9,10 @@ #![allow(clippy::needless_parens_on_range_literals)] #![allow(clippy::double_parens)] -#[macro_use] -extern crate macro_rules; - -macro_rules! a { - () => { - 'a' - }; -} -macro_rules! A { - () => { - 'A' - }; -} -macro_rules! zero { - () => { - '0' - }; -} - -macro_rules! b { - () => { - let _ = 'a'..'z'; - let _ = 'A'..'Z'; - let _ = '0'..'9'; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { #[rustfmt::skip] { @@ -56,9 +33,9 @@ fn main() { let _ = b'B'..b'Z'; let _ = b'1'..b'9'; - let _ = a!()..'z'; - let _ = A!()..'Z'; - let _ = zero!()..'9'; + let _ = inline!('a')..'z'; + let _ = inline!('A')..'Z'; + let _ = inline!('0')..'9'; let _ = match 0u8 { b'a'..b'z' if true => 1, @@ -80,8 +57,16 @@ fn main() { _ => 7, }; - almost_complete_range!(); - b!(); + external!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); + inline!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); } #[clippy::msrv = "1.25"] diff --git a/src/tools/clippy/tests/ui/almost_complete_range.stderr b/src/tools/clippy/tests/ui/almost_complete_range.stderr index a7a53287850..34521c13ab3 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.stderr +++ b/src/tools/clippy/tests/ui/almost_complete_range.stderr @@ -1,5 +1,5 @@ error: almost complete ascii range - --> $DIR/almost_complete_range.rs:42:17 + --> $DIR/almost_complete_range.rs:19:17 | LL | let _ = ('a') ..'z'; | ^^^^^^--^^^ @@ -9,7 +9,7 @@ LL | let _ = ('a') ..'z'; = note: `-D clippy::almost-complete-range` implied by `-D warnings` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:43:17 + --> $DIR/almost_complete_range.rs:20:17 | LL | let _ = 'A' .. ('Z'); | ^^^^--^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = 'A' .. ('Z'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:44:17 + --> $DIR/almost_complete_range.rs:21:17 | LL | let _ = ((('0'))) .. ('9'); | ^^^^^^^^^^--^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = ((('0'))) .. ('9'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:51:13 + --> $DIR/almost_complete_range.rs:28:13 | LL | let _ = (b'a')..(b'z'); | ^^^^^^--^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = (b'a')..(b'z'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:52:13 + --> $DIR/almost_complete_range.rs:29:13 | LL | let _ = b'A'..b'Z'; | ^^^^--^^^^ @@ -41,7 +41,7 @@ LL | let _ = b'A'..b'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:53:13 + --> $DIR/almost_complete_range.rs:30:13 | LL | let _ = b'0'..b'9'; | ^^^^--^^^^ @@ -49,31 +49,31 @@ LL | let _ = b'0'..b'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:59:13 + --> $DIR/almost_complete_range.rs:36:13 | -LL | let _ = a!()..'z'; - | ^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('a')..'z'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:60:13 + --> $DIR/almost_complete_range.rs:37:13 | -LL | let _ = A!()..'Z'; - | ^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('A')..'Z'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:61:13 + --> $DIR/almost_complete_range.rs:38:13 | -LL | let _ = zero!()..'9'; - | ^^^^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('0')..'9'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:64:9 + --> $DIR/almost_complete_range.rs:41:9 | LL | b'a'..b'z' if true => 1, | ^^^^--^^^^ @@ -81,7 +81,7 @@ LL | b'a'..b'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:65:9 + --> $DIR/almost_complete_range.rs:42:9 | LL | b'A'..b'Z' if true => 2, | ^^^^--^^^^ @@ -89,7 +89,7 @@ LL | b'A'..b'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:66:9 + --> $DIR/almost_complete_range.rs:43:9 | LL | b'0'..b'9' if true => 3, | ^^^^--^^^^ @@ -97,7 +97,7 @@ LL | b'0'..b'9' if true => 3, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:74:9 + --> $DIR/almost_complete_range.rs:51:9 | LL | 'a'..'z' if true => 1, | ^^^--^^^ @@ -105,7 +105,7 @@ LL | 'a'..'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:75:9 + --> $DIR/almost_complete_range.rs:52:9 | LL | 'A'..'Z' if true => 2, | ^^^--^^^ @@ -113,7 +113,7 @@ LL | 'A'..'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:76:9 + --> $DIR/almost_complete_range.rs:53:9 | LL | '0'..'9' if true => 3, | ^^^--^^^ @@ -121,46 +121,37 @@ LL | '0'..'9' if true => 3, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:33:17 + --> $DIR/almost_complete_range.rs:66:17 | LL | let _ = 'a'..'z'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:34:17 + --> $DIR/almost_complete_range.rs:67:17 | LL | let _ = 'A'..'Z'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:35:17 + --> $DIR/almost_complete_range.rs:68:17 | LL | let _ = '0'..'9'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:90:9 + --> $DIR/almost_complete_range.rs:75:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -168,7 +159,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:91:9 + --> $DIR/almost_complete_range.rs:76:9 | LL | 'A'..'Z' => 2, | ^^^--^^^ @@ -176,7 +167,7 @@ LL | 'A'..'Z' => 2, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:92:9 + --> $DIR/almost_complete_range.rs:77:9 | LL | '0'..'9' => 3, | ^^^--^^^ @@ -184,7 +175,7 @@ LL | '0'..'9' => 3, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:99:13 + --> $DIR/almost_complete_range.rs:84:13 | LL | let _ = 'a'..'z'; | ^^^--^^^ @@ -192,7 +183,7 @@ LL | let _ = 'a'..'z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:100:13 + --> $DIR/almost_complete_range.rs:85:13 | LL | let _ = 'A'..'Z'; | ^^^--^^^ @@ -200,7 +191,7 @@ LL | let _ = 'A'..'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:101:13 + --> $DIR/almost_complete_range.rs:86:13 | LL | let _ = '0'..'9'; | ^^^--^^^ @@ -208,7 +199,7 @@ LL | let _ = '0'..'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:103:9 + --> $DIR/almost_complete_range.rs:88:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -216,7 +207,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:104:9 + --> $DIR/almost_complete_range.rs:89:9 | LL | 'A'..'Z' => 1, | ^^^--^^^ @@ -224,7 +215,7 @@ LL | 'A'..'Z' => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:105:9 + --> $DIR/almost_complete_range.rs:90:9 | LL | '0'..'9' => 3, | ^^^--^^^ diff --git a/src/tools/clippy/tests/ui/as_conversions.rs b/src/tools/clippy/tests/ui/as_conversions.rs index ba4394defbf..c50d4088b5e 100644 --- a/src/tools/clippy/tests/ui/as_conversions.rs +++ b/src/tools/clippy/tests/ui/as_conversions.rs @@ -1,20 +1,15 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::as_conversions)] #![allow(clippy::borrow_as_ptr)] -#[macro_use] -extern crate macro_rules; - -fn with_external_macro() { - as_conv_with_arg!(0u32 as u64); - as_conv!(); -} +extern crate proc_macros; +use proc_macros::external; fn main() { let i = 0u32 as u64; let j = &i as *const u64 as *mut u64; - with_external_macro(); + external!(0u32 as u64); } diff --git a/src/tools/clippy/tests/ui/as_conversions.stderr b/src/tools/clippy/tests/ui/as_conversions.stderr index f5d59e1e5d8..54037a64997 100644 --- a/src/tools/clippy/tests/ui/as_conversions.stderr +++ b/src/tools/clippy/tests/ui/as_conversions.stderr @@ -1,5 +1,5 @@ error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:15:13 + --> $DIR/as_conversions.rs:10:13 | LL | let i = 0u32 as u64; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let i = 0u32 as u64; = note: `-D clippy::as-conversions` implied by `-D warnings` error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:17:13 + --> $DIR/as_conversions.rs:12:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let j = &i as *const u64 as *mut u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:17:13 + --> $DIR/as_conversions.rs:12:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/auxiliary/doc_unsafe_macros.rs b/src/tools/clippy/tests/ui/auxiliary/doc_unsafe_macros.rs deleted file mode 100644 index 3d917e3dc75..00000000000 --- a/src/tools/clippy/tests/ui/auxiliary/doc_unsafe_macros.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[macro_export] -macro_rules! undocd_unsafe { - () => { - pub unsafe fn oy_vey() { - unimplemented!(); - } - }; -} -#[macro_export] -macro_rules! undocd_safe { - () => { - pub fn vey_oy() { - unimplemented!(); - } - }; -} diff --git a/src/tools/clippy/tests/ui/auxiliary/implicit_hasher_macros.rs b/src/tools/clippy/tests/ui/auxiliary/implicit_hasher_macros.rs deleted file mode 100644 index 1eb77c53183..00000000000 --- a/src/tools/clippy/tests/ui/auxiliary/implicit_hasher_macros.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[macro_export] -macro_rules! implicit_hasher_fn { - () => { - pub fn f(input: &HashMap<u32, u32>) {} - }; -} diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs index a13af565203..a9bb61451dc 100644 --- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs +++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs @@ -3,21 +3,6 @@ //! Used to test that certain lints don't trigger in imported external macros #[macro_export] -macro_rules! foofoo { - () => { - loop {} - }; -} - -#[macro_export] -macro_rules! must_use_unit { - () => { - #[must_use] - fn foo() {} - }; -} - -#[macro_export] macro_rules! try_err { () => { pub fn try_err_fn() -> Result<i32, i32> { @@ -37,84 +22,6 @@ macro_rules! string_add { } #[macro_export] -macro_rules! take_external { - ($s:expr) => { - std::mem::replace($s, Default::default()) - }; -} - -#[macro_export] -macro_rules! option_env_unwrap_external { - ($env: expr) => { - option_env!($env).unwrap() - }; - ($env: expr, $message: expr) => { - option_env!($env).expect($message) - }; -} - -#[macro_export] -macro_rules! ref_arg_binding { - () => { - let ref _y = 42; - }; -} - -#[macro_export] -macro_rules! ref_arg_function { - () => { - fn fun_example(ref _x: usize) {} - }; -} - -#[macro_export] -macro_rules! as_conv_with_arg { - (0u32 as u64) => { - () - }; -} - -#[macro_export] -macro_rules! as_conv { - () => { - 0u32 as u64 - }; -} - -#[macro_export] -macro_rules! large_enum_variant { - () => { - enum LargeEnumInMacro { - A(i32), - B([i32; 8000]), - } - }; -} - -#[macro_export] -macro_rules! field_reassign_with_default { - () => { - #[derive(Default)] - struct A { - pub i: i32, - pub j: i64, - } - fn lint() { - let mut a: A = Default::default(); - a.i = 42; - a; - } - }; -} - -#[macro_export] -macro_rules! default_numeric_fallback { - () => { - let x = 22; - }; -} - -#[macro_export] macro_rules! mut_mut { () => { let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32; @@ -122,49 +29,11 @@ macro_rules! mut_mut { } #[macro_export] -macro_rules! ptr_as_ptr_cast { - ($ptr: ident) => { - $ptr as *const i32 - }; -} - -#[macro_export] -macro_rules! manual_rem_euclid { +macro_rules! issue_10421 { () => { - let value: i32 = 5; - let _: i32 = ((value % 4) + 4) % 4; - }; -} - -#[macro_export] -macro_rules! equatable_if_let { - ($a:ident) => {{ if let 2 = $a {} }}; -} - -#[macro_export] -macro_rules! almost_complete_range { - () => { - let _ = 'a'..'z'; - let _ = 'A'..'Z'; - let _ = '0'..'9'; - }; -} - -#[macro_export] -macro_rules! unsafe_macro { - () => { - unsafe { - *core::ptr::null::<()>(); - *core::ptr::null::<()>(); - } - }; -} - -#[macro_export] -macro_rules! needless_lifetime { - () => { - fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { - unimplemented!() - } + let mut a = 1; + let mut b = 2; + a = b; + b = a; }; } diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs b/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs index ecb55d8cb48..7ed8a28dbd9 100644 --- a/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs +++ b/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs @@ -13,7 +13,7 @@ pub mod inner { // RE-EXPORT // this will stick in `inner` module - pub use macro_rules::foofoo; + pub use macro_rules::mut_mut; pub use macro_rules::try_err; pub mod nested { diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_with_span.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_with_span.rs deleted file mode 100644 index 8ea631f2bbd..00000000000 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_with_span.rs +++ /dev/null @@ -1,32 +0,0 @@ -// compile-flags: --emit=link -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::{token_stream::IntoIter, Group, Span, TokenStream, TokenTree}; - -#[proc_macro] -pub fn with_span(input: TokenStream) -> TokenStream { - let mut iter = input.into_iter(); - let span = iter.next().unwrap().span(); - let mut res = TokenStream::new(); - write_with_span(span, iter, &mut res); - res -} - -fn write_with_span(s: Span, input: IntoIter, out: &mut TokenStream) { - for mut tt in input { - if let TokenTree::Group(g) = tt { - let mut stream = TokenStream::new(); - write_with_span(s, g.stream().into_iter(), &mut stream); - let mut group = Group::new(g.delimiter(), stream); - group.set_span(s); - out.extend([TokenTree::Group(group)]); - } else { - tt.set_span(s); - out.extend([tt]); - } - } -} diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs new file mode 100644 index 00000000000..325be83a0d7 --- /dev/null +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs @@ -0,0 +1,474 @@ +// compile-flags: --emit=link +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(let_chains)] +#![feature(proc_macro_span)] +#![allow(dead_code)] + +extern crate proc_macro; + +use core::mem; +use proc_macro::{ + token_stream::IntoIter, + Delimiter::{self, Brace, Parenthesis}, + Group, Ident, Literal, Punct, + Spacing::{self, Alone, Joint}, + Span, TokenStream, TokenTree as TT, +}; + +type Result<T> = core::result::Result<T, TokenStream>; + +/// Make a `compile_error!` pointing to the given span. +fn make_error(msg: &str, span: Span) -> TokenStream { + TokenStream::from_iter([ + TT::Ident(Ident::new("compile_error", span)), + TT::Punct(punct_with_span('!', Alone, span)), + TT::Group({ + let mut msg = Literal::string(msg); + msg.set_span(span); + group_with_span(Parenthesis, TokenStream::from_iter([TT::Literal(msg)]), span) + }), + ]) +} + +fn expect_tt<T>(tt: Option<TT>, f: impl FnOnce(TT) -> Option<T>, expected: &str, span: Span) -> Result<T> { + match tt { + None => Err(make_error( + &format!("unexpected end of input, expected {expected}"), + span, + )), + Some(tt) => { + let span = tt.span(); + match f(tt) { + Some(x) => Ok(x), + None => Err(make_error(&format!("unexpected token, expected {expected}"), span)), + } + }, + } +} + +fn punct_with_span(c: char, spacing: Spacing, span: Span) -> Punct { + let mut p = Punct::new(c, spacing); + p.set_span(span); + p +} + +fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Group { + let mut g = Group::new(delimiter, stream); + g.set_span(span); + g +} + +/// Token used to escape the following token from the macro's span rules. +const ESCAPE_CHAR: char = '$'; + +/// Takes a single token followed by a sequence tokens. Returns the sequence of tokens with their +/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`. +#[proc_macro] +pub fn with_span(input: TokenStream) -> TokenStream { + let mut iter = input.into_iter(); + let span = iter.next().unwrap().span(); + let mut res = TokenStream::new(); + if let Err(e) = write_with_span(span, iter, &mut res) { + e + } else { + res + } +} + +/// Takes a sequence of tokens and return the tokens with the span set such that they appear to be +/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`. +#[proc_macro] +pub fn external(input: TokenStream) -> TokenStream { + let mut res = TokenStream::new(); + if let Err(e) = write_with_span(Span::mixed_site(), input.into_iter(), &mut res) { + e + } else { + res + } +} + +/// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped +/// either by `#ident` or `#(tokens)`. +fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> { + while let Some(tt) = input.next() { + match tt { + TT::Punct(p) if p.as_char() == ESCAPE_CHAR => { + expect_tt( + input.next(), + |tt| match tt { + tt @ (TT::Ident(_) | TT::Literal(_)) => { + out.extend([tt]); + Some(()) + }, + TT::Punct(mut p) if p.as_char() == ESCAPE_CHAR => { + p.set_span(s); + out.extend([TT::Punct(p)]); + Some(()) + }, + TT::Group(g) if g.delimiter() == Parenthesis => { + out.extend([TT::Group(group_with_span(Delimiter::None, g.stream(), g.span()))]); + Some(()) + }, + _ => None, + }, + "an ident, a literal, or parenthesized tokens", + p.span(), + )?; + }, + TT::Group(g) => { + let mut stream = TokenStream::new(); + write_with_span(s, g.stream().into_iter(), &mut stream)?; + out.extend([TT::Group(group_with_span(g.delimiter(), stream, s))]); + }, + mut tt => { + tt.set_span(s); + out.extend([tt]); + }, + } + } + Ok(()) +} + +/// Within the item this attribute is attached to, an `inline!` macro is available which expands the +/// contained tokens as though they came from a macro expansion. +/// +/// Within the `inline!` macro, any token preceded by `$` is passed as though it were an argument +/// with an automatically chosen fragment specifier. `$ident` will be passed as `ident`, `$1` or +/// `$"literal"` will be passed as `literal`, `$'lt` will be passed as `lifetime`, and `$(...)` will +/// pass the contained tokens as a `tt` sequence (the wrapping parenthesis are removed). If another +/// specifier is required it can be specified within parenthesis like `$(@expr ...)`. This will +/// expand the remaining tokens as a single argument. +/// +/// Multiple `inline!` macros may be nested within each other. This will expand as nested macro +/// calls. However, any arguments will be passed as though they came from the outermost context. +#[proc_macro_attribute] +pub fn inline_macros(args: TokenStream, input: TokenStream) -> TokenStream { + let mut args = args.into_iter(); + let mac_name = match args.next() { + Some(TT::Ident(name)) => Some(name), + Some(tt) => { + return make_error( + "unexpected argument, expected either an ident or no arguments", + tt.span(), + ); + }, + None => None, + }; + if let Some(tt) = args.next() { + return make_error( + "unexpected argument, expected either an ident or no arguments", + tt.span(), + ); + }; + + let mac_name = if let Some(mac_name) = mac_name { + Ident::new(&format!("__inline_mac_{mac_name}"), Span::call_site()) + } else { + let mut input = match LookaheadIter::new(input.clone().into_iter()) { + Some(x) => x, + None => return input, + }; + loop { + match input.next() { + None => break Ident::new("__inline_mac", Span::call_site()), + Some(TT::Ident(kind)) => match &*kind.to_string() { + "impl" => break Ident::new("__inline_mac_impl", Span::call_site()), + kind @ ("struct" | "enum" | "union" | "fn" | "mod" | "trait" | "type" | "const" | "static") => { + if let TT::Ident(name) = &input.tt { + break Ident::new(&format!("__inline_mac_{kind}_{name}"), Span::call_site()); + } else { + break Ident::new(&format!("__inline_mac_{kind}"), Span::call_site()); + } + }, + _ => {}, + }, + _ => {}, + } + } + }; + + let mut expander = Expander::default(); + let mut mac = MacWriter::new(mac_name); + if let Err(e) = expander.expand(input.into_iter(), &mut mac) { + return e; + } + let mut out = TokenStream::new(); + mac.finish(&mut out); + out.extend(expander.expn); + out +} + +/// Wraps a `TokenStream` iterator with a single token lookahead. +struct LookaheadIter { + tt: TT, + iter: IntoIter, +} +impl LookaheadIter { + fn new(mut iter: IntoIter) -> Option<Self> { + iter.next().map(|tt| Self { tt, iter }) + } + + /// Get's the lookahead token, replacing it with the next token in the stream. + /// Note: If there isn't a next token, this will not return the lookahead token. + fn next(&mut self) -> Option<TT> { + self.iter.next().map(|tt| mem::replace(&mut self.tt, tt)) + } +} + +/// Builds the macro used to implement all the `inline!` macro calls. +struct MacWriter { + name: Ident, + macros: TokenStream, + next_idx: usize, +} +impl MacWriter { + fn new(name: Ident) -> Self { + Self { + name, + macros: TokenStream::new(), + next_idx: 0, + } + } + + /// Inserts a new `inline!` call. + fn insert(&mut self, name_span: Span, bang_span: Span, body: Group, expander: &mut Expander) -> Result<()> { + let idx = self.next_idx; + self.next_idx += 1; + + let mut inner = Expander::for_arm(idx); + inner.expand(body.stream().into_iter(), self)?; + let new_arm = inner.arm.unwrap(); + + self.macros.extend([ + TT::Group(Group::new(Parenthesis, new_arm.args_def)), + TT::Punct(Punct::new('=', Joint)), + TT::Punct(Punct::new('>', Alone)), + TT::Group(Group::new(Parenthesis, inner.expn)), + TT::Punct(Punct::new(';', Alone)), + ]); + + expander.expn.extend([ + TT::Ident({ + let mut name = self.name.clone(); + name.set_span(name_span); + name + }), + TT::Punct(punct_with_span('!', Alone, bang_span)), + ]); + let mut call_body = TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]); + if let Some(arm) = expander.arm.as_mut() { + if !new_arm.args.is_empty() { + arm.add_sub_args(new_arm.args, &mut call_body); + } + } else { + call_body.extend(new_arm.args); + } + let mut g = Group::new(body.delimiter(), call_body); + g.set_span(body.span()); + expander.expn.extend([TT::Group(g)]); + Ok(()) + } + + /// Creates the macro definition. + fn finish(self, out: &mut TokenStream) { + if self.next_idx != 0 { + out.extend([ + TT::Ident(Ident::new("macro_rules", Span::call_site())), + TT::Punct(Punct::new('!', Alone)), + TT::Ident(self.name), + TT::Group(Group::new(Brace, self.macros)), + ]) + } + } +} + +struct MacroArm { + args_def: TokenStream, + args: Vec<TT>, +} +impl MacroArm { + fn add_single_arg_def(&mut self, kind: &str, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(Ident::new(kind, Span::call_site())), + ]); + name.set_span(arg_span); + out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]); + } + + fn add_parenthesized_arg_def(&mut self, kind: Ident, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(kind), + ]), + ))]); + name.set_span(arg_span); + out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]); + } + + fn add_multi_arg_def(&mut self, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(Ident::new("tt", Span::call_site())), + ]), + )), + TT::Punct(Punct::new('*', Alone)), + ]), + ))]); + name.set_span(arg_span); + out.extend([ + TT::Punct(punct_with_span('$', Alone, dollar_span)), + TT::Group(group_with_span( + Parenthesis, + TokenStream::from_iter([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]), + dollar_span, + )), + TT::Punct(punct_with_span('*', Alone, dollar_span)), + ]); + } + + fn add_arg(&mut self, dollar_span: Span, tt: TT, input: &mut IntoIter, out: &mut TokenStream) -> Result<()> { + match tt { + TT::Punct(p) if p.as_char() == ESCAPE_CHAR => out.extend([TT::Punct(p)]), + TT::Punct(p) if p.as_char() == '\'' && p.spacing() == Joint => { + let lt_name = expect_tt( + input.next(), + |tt| match tt { + TT::Ident(x) => Some(x), + _ => None, + }, + "lifetime name", + p.span(), + )?; + let arg_span = p.span().join(lt_name.span()).unwrap_or(p.span()); + self.add_single_arg_def("lifetime", dollar_span, arg_span, out); + self.args.extend([TT::Punct(p), TT::Ident(lt_name)]); + }, + TT::Ident(x) => { + self.add_single_arg_def("ident", dollar_span, x.span(), out); + self.args.push(TT::Ident(x)); + }, + TT::Literal(x) => { + self.add_single_arg_def("literal", dollar_span, x.span(), out); + self.args.push(TT::Literal(x)); + }, + TT::Group(g) if g.delimiter() == Parenthesis => { + let mut inner = g.stream().into_iter(); + if let Some(TT::Punct(p)) = inner.next() + && p.as_char() == '@' + { + let kind = expect_tt( + inner.next(), + |tt| match tt { + TT::Ident(kind) => Some(kind), + _ => None, + }, + "a macro fragment specifier", + p.span(), + )?; + self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out); + self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span()))) + } else { + self.add_multi_arg_def(dollar_span, g.span(), out); + self.args.push(TT::Group(g)); + } + }, + tt => return Err(make_error("unsupported escape", tt.span())), + }; + Ok(()) + } + + fn add_sub_args(&mut self, args: Vec<TT>, out: &mut TokenStream) { + self.add_multi_arg_def(Span::call_site(), Span::call_site(), out); + self.args + .extend([TT::Group(Group::new(Parenthesis, TokenStream::from_iter(args)))]); + } +} + +#[derive(Default)] +struct Expander { + arm: Option<MacroArm>, + expn: TokenStream, +} +impl Expander { + fn for_arm(idx: usize) -> Self { + Self { + arm: Some(MacroArm { + args_def: TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]), + args: Vec::new(), + }), + expn: TokenStream::new(), + } + } + + fn write_tt(&mut self, tt: TT, mac: &mut MacWriter) -> Result<()> { + match tt { + TT::Group(g) => { + let outer = mem::take(&mut self.expn); + self.expand(g.stream().into_iter(), mac)?; + let inner = mem::replace(&mut self.expn, outer); + self.expn + .extend([TT::Group(group_with_span(g.delimiter(), inner, g.span()))]); + }, + tt => self.expn.extend([tt]), + } + Ok(()) + } + + fn expand(&mut self, input: IntoIter, mac: &mut MacWriter) -> Result<()> { + let Some(mut input) = LookaheadIter::new(input) else { + return Ok(()); + }; + while let Some(tt) = input.next() { + if let TT::Punct(p) = &tt + && p.as_char() == ESCAPE_CHAR + && let Some(arm) = self.arm.as_mut() + { + arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?; + if input.next().is_none() { + return Ok(()); + } + } else if let TT::Punct(p) = &input.tt + && p.as_char() == '!' + && let TT::Ident(name) = &tt + && name.to_string() == "inline" + { + let g = expect_tt( + input.iter.next(), + |tt| match tt { + TT::Group(g) => Some(g), + _ => None, + }, + "macro arguments", + p.span(), + )?; + mac.insert(name.span(), p.span(), g, self)?; + if input.next().is_none() { + return Ok(()); + } + } else { + self.write_tt(tt, mac)?; + } + } + self.write_tt(input.tt, mac) + } +} diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs index f13733af3d0..b03c21262c3 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs @@ -1,5 +1,5 @@ // this file solely exists to test constants defined in foreign crates. -// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure. +// As the most common case is the `http` crate, it replicates `http::HeaderName`'s structure. #![allow(clippy::declare_interior_mutable_const)] #![allow(unused_tuple_struct_fields)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-10148.rs b/src/tools/clippy/tests/ui/crashes/ice-10148.rs index af33b10c693..1ab3570c907 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10148.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-10148.rs @@ -1,8 +1,8 @@ -// aux-build:../../auxiliary/proc_macro_with_span.rs +// aux-build:../../auxiliary/proc_macros.rs -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; fn main() { println!(with_span!(""something "")); diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed index a9e5fd159af..42c15d6a70b 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -167,20 +167,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22.0_f64; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22.0_f64;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22.;); } } diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs index 085f8f452b2..7da7ea254e9 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -167,20 +167,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22.; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22.;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22.;); } } diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr index 44c6f1a9bea..b949cd1d50b 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr @@ -139,15 +139,12 @@ LL | s.generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:172:21 + --> $DIR/default_numeric_fallback_f64.rs:175:25 | -LL | let x = 22.; - | ^^^ help: consider adding suffix: `22.0_f64` -... -LL | internal_macro!(); - | ----------------- in this macro invocation +LL | inline!(let x = 22.;); + | ^^^ help: consider adding suffix: `22.0_f64` | - = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed index 63ac4d5aeb6..b7485b73dcd 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -168,20 +168,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22_i32; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22_i32;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22;); } } diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs index 28e6eceb80e..7307d31354e 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -168,20 +168,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22;); } } diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr index dd91574d5b3..48cd28102ce 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr @@ -151,15 +151,12 @@ LL | s.generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:173:21 + --> $DIR/default_numeric_fallback_i32.rs:176:25 | -LL | let x = 22; - | ^^ help: consider adding suffix: `22_i32` -... -LL | internal_macro!(); - | ----------------- in this macro invocation +LL | inline!(let x = 22;); + | ^^ help: consider adding suffix: `22_i32` | - = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed index 5640599d48a..7842ef3ec40 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.fixed +++ b/src/tools/clippy/tests/ui/default_trait_access.fixed @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::default; use std::default::Default as D2; use std::string; diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs index 11d4bc5c5f0..cbb3e59c970 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.rs +++ b/src/tools/clippy/tests/ui/default_trait_access.rs @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::default; use std::default::Default as D2; use std::string; diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed index 2f489deb1ee..ca5c03304c7 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.fixed +++ b/src/tools/clippy/tests/ui/deref_addrof.fixed @@ -1,7 +1,12 @@ // run-rustfix +// aux-build:proc_macros.rs + #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] +extern crate proc_macros; +use proc_macros::inline_macros; + fn get_number() -> usize { 10 } @@ -41,28 +46,15 @@ fn main() { let _ = unsafe { *core::ptr::addr_of!(a) }; } -#[rustfmt::skip] -macro_rules! m { - ($visitor: expr) => { - $visitor - }; -} - -#[rustfmt::skip] -macro_rules! m_mut { - ($visitor: expr) => { - $visitor - }; -} - #[derive(Copy, Clone)] pub struct S; +#[inline_macros] impl S { pub fn f(&self) -> &Self { - m!(self) + inline!($(@expr self)) } #[allow(unused_mut)] // mut will be unused, once the macro is fixed pub fn f_mut(mut self) -> Self { - m_mut!(self) + inline!($(@expr self)) } } diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs index 49f360b9a7f..3db5fafe944 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.rs +++ b/src/tools/clippy/tests/ui/deref_addrof.rs @@ -1,7 +1,12 @@ // run-rustfix +// aux-build:proc_macros.rs + #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] +extern crate proc_macros; +use proc_macros::inline_macros; + fn get_number() -> usize { 10 } @@ -41,28 +46,15 @@ fn main() { let _ = unsafe { *core::ptr::addr_of!(a) }; } -#[rustfmt::skip] -macro_rules! m { - ($visitor: expr) => { - *& $visitor - }; -} - -#[rustfmt::skip] -macro_rules! m_mut { - ($visitor: expr) => { - *& mut $visitor - }; -} - #[derive(Copy, Clone)] pub struct S; +#[inline_macros] impl S { pub fn f(&self) -> &Self { - m!(self) + inline!(*& $(@expr self)) } #[allow(unused_mut)] // mut will be unused, once the macro is fixed pub fn f_mut(mut self) -> Self { - m_mut!(self) + inline!(*&mut $(@expr self)) } } diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr index 75371fcdb96..e0287522fc5 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof.stderr @@ -1,5 +1,5 @@ error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:19:13 + --> $DIR/deref_addrof.rs:24:13 | LL | let b = *&a; | ^^^ help: try this: `a` @@ -7,68 +7,62 @@ LL | let b = *&a; = note: `-D clippy::deref-addrof` implied by `-D warnings` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:21:13 + --> $DIR/deref_addrof.rs:26:13 | LL | let b = *&get_number(); | ^^^^^^^^^^^^^^ help: try this: `get_number()` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:26:13 + --> $DIR/deref_addrof.rs:31:13 | LL | let b = *&bytes[1..2][0]; | ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:30:13 + --> $DIR/deref_addrof.rs:35:13 | LL | let b = *&(a); | ^^^^^ help: try this: `(a)` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:32:13 + --> $DIR/deref_addrof.rs:37:13 | LL | let b = *(&a); | ^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:35:13 + --> $DIR/deref_addrof.rs:40:13 | LL | let b = *((&a)); | ^^^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:37:13 + --> $DIR/deref_addrof.rs:42:13 | LL | let b = *&&a; | ^^^^ help: try this: `&a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:39:14 + --> $DIR/deref_addrof.rs:44:14 | LL | let b = **&aref; | ^^^^^^ help: try this: `aref` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:47:9 + --> $DIR/deref_addrof.rs:54:17 | -LL | *& $visitor - | ^^^^^^^^^^^ help: try this: `$visitor` -... -LL | m!(self) - | -------- in this macro invocation +LL | inline!(*& $(@expr self)) + | ^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)` | - = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:54:9 + --> $DIR/deref_addrof.rs:58:17 | -LL | *& mut $visitor - | ^^^^^^^^^^^^^^^ help: try this: `$visitor` -... -LL | m_mut!(self) - | ------------ in this macro invocation +LL | inline!(*&mut $(@expr self)) + | ^^^^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)` | - = note: this error originates in the macro `m_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/deref_addrof_macro.rs b/src/tools/clippy/tests/ui/deref_addrof_macro.rs index dcebd6c6e29..57c0be3f51e 100644 --- a/src/tools/clippy/tests/ui/deref_addrof_macro.rs +++ b/src/tools/clippy/tests/ui/deref_addrof_macro.rs @@ -1,10 +1,13 @@ -macro_rules! m { - ($($x:tt),*) => { &[$(($x, stringify!(x)),)*] }; -} +// aux-build:proc_macros.rs + +#![warn(clippy::deref_addrof)] + +extern crate proc_macros; -#[warn(clippy::deref_addrof)] -fn f() -> [(i32, &'static str); 3] { - *m![1, 2, 3] // should be fine +#[proc_macros::inline_macros] +fn f() -> i32 { + // should be fine + *inline!(&$1) } fn main() {} diff --git a/src/tools/clippy/tests/ui/doc_unsafe.rs b/src/tools/clippy/tests/ui/doc_unsafe.rs index b91f7aa0dd8..30674ce3708 100644 --- a/src/tools/clippy/tests/ui/doc_unsafe.rs +++ b/src/tools/clippy/tests/ui/doc_unsafe.rs @@ -1,9 +1,9 @@ -// aux-build:doc_unsafe_macros.rs +// aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] -#[macro_use] -extern crate doc_unsafe_macros; +extern crate proc_macros; +use proc_macros::external; /// This is not sufficiently documented pub unsafe fn destroy_the_planet() { @@ -105,7 +105,11 @@ macro_rules! very_unsafe { very_unsafe!(); // we don't lint code from external macros -undocd_unsafe!(); +external! { + pub unsafe fn oy_vey() { + unimplemented!(); + } +} fn main() { unsafe { diff --git a/src/tools/clippy/tests/ui/empty_loop.rs b/src/tools/clippy/tests/ui/empty_loop.rs index 8fd7697eb3b..6a8e6b550c1 100644 --- a/src/tools/clippy/tests/ui/empty_loop.rs +++ b/src/tools/clippy/tests/ui/empty_loop.rs @@ -1,9 +1,9 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::empty_loop)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn should_trigger() { loop {} @@ -16,6 +16,7 @@ fn should_trigger() { } } +#[inline_macros] fn should_not_trigger() { loop { panic!("This is fine") @@ -38,14 +39,10 @@ fn should_not_trigger() { loop {} // We don't lint loops inside macros - macro_rules! foo { - () => { - loop {} - }; - } + inline!(loop {}); // We don't lint external macros - foofoo!() + external!(loop {}); } fn main() {} diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed index 9af2ba96272..007702ab550 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.fixed +++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -44,6 +44,7 @@ impl PartialEq for NotStructuralEq { } } +#[inline_macros] fn main() { let a = 2; let b = 3; @@ -78,14 +79,9 @@ fn main() { if Some(g) == Some(NotStructuralEq::A) {} if matches!(h, NoPartialEqStruct { a: 2, b: false }) {} - macro_rules! m1 { - (x) => { - "abc" - }; - } - if "abc" == m1!(x) { + if "abc" == inline!("abc") { println!("OK"); } - equatable_if_let!(a); + external!({ if let 2 = $a {} }); } diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs index c3626c081dd..3bda7977645 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.rs +++ b/src/tools/clippy/tests/ui/equatable_if_let.rs @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -44,6 +44,7 @@ impl PartialEq for NotStructuralEq { } } +#[inline_macros] fn main() { let a = 2; let b = 3; @@ -78,14 +79,9 @@ fn main() { if let Some(NotStructuralEq::A) = Some(g) {} if let NoPartialEqStruct { a: 2, b: false } = h {} - macro_rules! m1 { - (x) => { - "abc" - }; - } - if let m1!(x) = "abc" { + if let inline!("abc") = "abc" { println!("OK"); } - equatable_if_let!(a); + external!({ if let 2 = $a {} }); } diff --git a/src/tools/clippy/tests/ui/equatable_if_let.stderr b/src/tools/clippy/tests/ui/equatable_if_let.stderr index 40ca75b8da2..a72d87bb7ba 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.stderr +++ b/src/tools/clippy/tests/ui/equatable_if_let.stderr @@ -1,5 +1,5 @@ error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:59:8 + --> $DIR/equatable_if_let.rs:60:8 | LL | if let 2 = a {} | ^^^^^^^^^ help: try: `a == 2` @@ -7,82 +7,82 @@ LL | if let 2 = a {} = note: `-D clippy::equatable-if-let` implied by `-D warnings` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:60:8 + --> $DIR/equatable_if_let.rs:61:8 | LL | if let Ordering::Greater = a.cmp(&b) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:61:8 + --> $DIR/equatable_if_let.rs:62:8 | LL | if let Some(2) = c {} | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:62:8 + --> $DIR/equatable_if_let.rs:63:8 | LL | if let Struct { a: 2, b: false } = d {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:63:8 + --> $DIR/equatable_if_let.rs:64:8 | LL | if let Enum::TupleVariant(32, 64) = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:64:8 + --> $DIR/equatable_if_let.rs:65:8 | LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:65:8 + --> $DIR/equatable_if_let.rs:66:8 | LL | if let Enum::UnitVariant = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:66:8 + --> $DIR/equatable_if_let.rs:67:8 | LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:75:8 + --> $DIR/equatable_if_let.rs:76:8 | LL | if let NotPartialEq::A = f {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:76:8 + --> $DIR/equatable_if_let.rs:77:8 | LL | if let NotStructuralEq::A = g {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:77:8 + --> $DIR/equatable_if_let.rs:78:8 | LL | if let Some(NotPartialEq::A) = Some(f) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:78:8 + --> $DIR/equatable_if_let.rs:79:8 | LL | if let Some(NotStructuralEq::A) = Some(g) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:79:8 + --> $DIR/equatable_if_let.rs:80:8 | LL | if let NoPartialEqStruct { a: 2, b: false } = h {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:86:8 + --> $DIR/equatable_if_let.rs:82:8 | -LL | if let m1!(x) = "abc" { - | ^^^^^^^^^^^^^^^^^^ help: try: `"abc" == m1!(x)` +LL | if let inline!("abc") = "abc" { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs index 1f989bb1220..0e208b3ed0e 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.rs +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs @@ -1,12 +1,12 @@ // aux-build:proc_macro_derive.rs -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::field_reassign_with_default)] #[macro_use] extern crate proc_macro_derive; -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; // Don't lint on derives that derive `Default` // See https://github.com/rust-lang/rust-clippy/issues/6545 @@ -36,14 +36,6 @@ struct D { b: Option<i32>, } -macro_rules! m { - ($key:ident: $value:tt) => {{ - let mut data = $crate::D::default(); - data.$key = Some($value); - data - }}; -} - /// Implements .next() that returns a different number each time. struct SideEffect(i32); @@ -57,6 +49,7 @@ impl SideEffect { } } +#[inline_macros] fn main() { // wrong, produces first error in stderr let mut a: A = Default::default(); @@ -150,7 +143,18 @@ fn main() { a.i = vec![1]; // Don't lint in external macros - field_reassign_with_default!(); + external! { + #[derive(Default)] + struct A { + pub i: i32, + pub j: i64, + } + fn lint() { + let mut a: A = Default::default(); + a.i = 42; + a; + } + } // be sure suggestion is correct with generics let mut a: Wrapper<bool> = Default::default(); @@ -160,9 +164,11 @@ fn main() { a.i = 42; // Don't lint in macros - m! { - a: 42 - }; + inline!( + let mut data = $crate::D::default(); + data.$a = Some($42); + data + ); } mod m { diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr index 710bb66a48a..da74f9ef9f7 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr @@ -1,132 +1,132 @@ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:63:5 + --> $DIR/field_reassign_with_default.rs:56:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:62:5 + --> $DIR/field_reassign_with_default.rs:55:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::field-reassign-with-default` implied by `-D warnings` error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:103:5 + --> $DIR/field_reassign_with_default.rs:96:5 | LL | a.j = 43; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:102:5 + --> $DIR/field_reassign_with_default.rs:95:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:108:5 + --> $DIR/field_reassign_with_default.rs:101:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:107:5 + --> $DIR/field_reassign_with_default.rs:100:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:114:5 + --> $DIR/field_reassign_with_default.rs:107:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:113:5 + --> $DIR/field_reassign_with_default.rs:106:5 | LL | let mut a = A::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:124:5 + --> $DIR/field_reassign_with_default.rs:117:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:123:5 + --> $DIR/field_reassign_with_default.rs:116:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:128:5 + --> $DIR/field_reassign_with_default.rs:121:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:127:5 + --> $DIR/field_reassign_with_default.rs:120:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:150:5 + --> $DIR/field_reassign_with_default.rs:143:5 | LL | a.i = vec![1]; | ^^^^^^^^^^^^^^ | note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:149:5 + --> $DIR/field_reassign_with_default.rs:142:5 | LL | let mut a: C = C::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:157:5 + --> $DIR/field_reassign_with_default.rs:161:5 | LL | a.i = true; | ^^^^^^^^^^^ | note: consider initializing the variable with `Wrapper::<bool> { i: true }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:156:5 + --> $DIR/field_reassign_with_default.rs:160:5 | LL | let mut a: Wrapper<bool> = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:160:5 + --> $DIR/field_reassign_with_default.rs:164:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `WrapperMulti::<i32, i64> { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:159:5 + --> $DIR/field_reassign_with_default.rs:163:5 | LL | let mut a: WrapperMulti<i32, i64> = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:229:13 + --> $DIR/field_reassign_with_default.rs:235:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:228:13 + --> $DIR/field_reassign_with_default.rs:234:13 | LL | let mut f = ImplDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:245:13 + --> $DIR/field_reassign_with_default.rs:251:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:244:13 + --> $DIR/field_reassign_with_default.rs:250:13 | LL | let mut f = NoDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs index 9850fc0919e..9ce9a87626a 100644 --- a/src/tools/clippy/tests/ui/ifs_same_cond.rs +++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs @@ -43,4 +43,30 @@ fn ifs_same_cond() { } } +fn issue10272() { + let a = String::from("ha"); + if a.contains("ah") { + } else if a.contains("ah") { + // Trigger this lint + } else if a.contains("ha") { + } else if a == "wow" { + } + + let p: *mut i8 = std::ptr::null_mut(); + if p.is_null() { + } else if p.align_offset(0) == 0 { + } else if p.is_null() { + // ok, p is mutable pointer + } else { + } + + let x = std::cell::Cell::new(true); + if x.get() { + } else if !x.take() { + } else if x.get() { + // ok, x is interior mutable type + } else { + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr index 4113087327a..9519f6904cb 100644 --- a/src/tools/clippy/tests/ui/ifs_same_cond.stderr +++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr @@ -35,5 +35,17 @@ note: same as this LL | if 2 * a == 1 { | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: this `if` has the same condition as a previous `if` + --> $DIR/ifs_same_cond.rs:49:15 + | +LL | } else if a.contains("ah") { + | ^^^^^^^^^^^^^^^^ + | +note: same as this + --> $DIR/ifs_same_cond.rs:48:8 + | +LL | if a.contains("ah") { + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs index fd96ca3f466..35d08a07bc3 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.rs +++ b/src/tools/clippy/tests/ui/implicit_hasher.rs @@ -1,9 +1,11 @@ -// aux-build:implicit_hasher_macros.rs +// aux-build:proc_macros.rs + #![deny(clippy::implicit_hasher)] #![allow(unused)] #[macro_use] -extern crate implicit_hasher_macros; +extern crate proc_macros; +use proc_macros::external; use std::cmp::Eq; use std::collections::{HashMap, HashSet}; @@ -68,22 +70,19 @@ impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> { pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} -macro_rules! gen { - (impl) => { +#[proc_macros::inline_macros] +pub mod gen { + use super::*; + inline! { impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> { fn make() -> (Self, Self) { (HashMap::new(), HashMap::with_capacity(10)) } } - }; - (fn $name:ident) => { - pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} - }; + pub fn bar(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} + } } -#[rustfmt::skip] -gen!(impl); -gen!(fn bar); // When the macro is in a different file, the suggestion spans can't be combined properly // and should not cause an ICE @@ -94,7 +93,9 @@ pub mod test_macro; __implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A); // #4260 -implicit_hasher_fn!(); +external! { + pub fn f(input: &HashMap<u32, u32>) {} +} // #7712 pub async fn election_vote(_data: HashMap<i32, i32>) {} diff --git a/src/tools/clippy/tests/ui/implicit_hasher.stderr b/src/tools/clippy/tests/ui/implicit_hasher.stderr index 59b0fba2a4c..83b46de2eb5 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.stderr +++ b/src/tools/clippy/tests/ui/implicit_hasher.stderr @@ -1,11 +1,11 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:16:35 + --> $DIR/implicit_hasher.rs:18:35 | LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> { | ^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/implicit_hasher.rs:2:9 + --> $DIR/implicit_hasher.rs:3:9 | LL | #![deny(clippy::implicit_hasher)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:25:36 + --> $DIR/implicit_hasher.rs:27:36 | LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) { | ^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:30:19 + --> $DIR/implicit_hasher.rs:32:19 | LL | impl Foo<i16> for HashMap<String, String> { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:47:32 + --> $DIR/implicit_hasher.rs:49:32 | LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> { | ^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:52:19 + --> $DIR/implicit_hasher.rs:54:19 | LL | impl Foo<i16> for HashSet<String> { | ^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:23 + --> $DIR/implicit_hasher.rs:71:23 | LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _s | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:53 + --> $DIR/implicit_hasher.rs:71:53 | LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^ @@ -101,15 +101,12 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:73:43 + --> $DIR/implicit_hasher.rs:77:43 | LL | impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> { | ^^^^^^^^^^^^^ -... -LL | gen!(impl); - | ---------- in this macro invocation | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> { @@ -120,37 +117,31 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:33 + --> $DIR/implicit_hasher.rs:83:31 | -LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} - | ^^^^^^^^^^^^^^^^^ -... -LL | gen!(fn bar); - | ------------ in this macro invocation +LL | pub fn bar(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} + | ^^^^^^^^^^^^^^^^^ | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | -LL | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {} - | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ +LL | pub fn bar<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {} + | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:63 + --> $DIR/implicit_hasher.rs:83:61 | -LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} - | ^^^^^^^^^^^^ -... -LL | gen!(fn bar); - | ------------ in this macro invocation +LL | pub fn bar(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} + | ^^^^^^^^^^^^ | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | -LL | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {} - | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ +LL | pub fn bar<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {} + | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:100:35 + --> $DIR/implicit_hasher.rs:101:35 | LL | pub async fn election_vote(_data: HashMap<i32, i32>) {} | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed index 74ba2f1c5e7..5aaa00f8517 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed @@ -1,10 +1,14 @@ // run-rustfix +// aux-build:proc_macros.rs + #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::no_effect)] #![allow(dead_code)] +extern crate proc_macros; + #[derive(Default)] struct Foo { x: i32, @@ -12,18 +16,10 @@ struct Foo { z: i32, } -macro_rules! new_foo { - () => { - let x = 1; - let y = 1; - let z = 1; - Foo { y, x, z } - }; -} - mod without_base { use super::Foo; + #[proc_macros::inline_macros] fn test() { let x = 1; let y = 1; @@ -34,7 +30,12 @@ mod without_base { // Should NOT lint. // issue #7069. - new_foo!(); + inline!({ + let x = 1; + let y = 1; + let z = 1; + Foo { y, x, z } + }); // Should NOT lint because the order is the same as in the definition. Foo { x, y, z }; diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs index ba96e1e330f..2b2dd7f59a4 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs @@ -1,10 +1,14 @@ // run-rustfix +// aux-build:proc_macros.rs + #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::no_effect)] #![allow(dead_code)] +extern crate proc_macros; + #[derive(Default)] struct Foo { x: i32, @@ -12,18 +16,10 @@ struct Foo { z: i32, } -macro_rules! new_foo { - () => { - let x = 1; - let y = 1; - let z = 1; - Foo { y, x, z } - }; -} - mod without_base { use super::Foo; + #[proc_macros::inline_macros] fn test() { let x = 1; let y = 1; @@ -34,7 +30,12 @@ mod without_base { // Should NOT lint. // issue #7069. - new_foo!(); + inline!({ + let x = 1; + let y = 1; + let z = 1; + Foo { y, x, z } + }); // Should NOT lint because the order is the same as in the definition. Foo { x, y, z }; diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr index c90189e964f..785a6dc9d53 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr @@ -1,5 +1,5 @@ error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:33:9 + --> $DIR/inconsistent_struct_constructor.rs:29:9 | LL | Foo { y, x, z }; | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` @@ -7,7 +7,7 @@ LL | Foo { y, x, z }; = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:55:9 + --> $DIR/inconsistent_struct_constructor.rs:56:9 | LL | / Foo { LL | | z, diff --git a/src/tools/clippy/tests/ui/large_enum_variant.rs b/src/tools/clippy/tests/ui/large_enum_variant.rs index 3b96f09d7b1..f09f8ae0ccc 100644 --- a/src/tools/clippy/tests/ui/large_enum_variant.rs +++ b/src/tools/clippy/tests/ui/large_enum_variant.rs @@ -1,11 +1,11 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(dead_code)] #![allow(unused_variables)] #![warn(clippy::large_enum_variant)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; enum LargeEnum { A(i32), @@ -155,5 +155,10 @@ enum LargeEnumOfConst { } fn main() { - large_enum_variant!(); + external!( + enum LargeEnumInMacro { + A(i32), + B([i32; 8000]), + } + ); } diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index e612480d264..15f7a099a7d 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -20,7 +20,7 @@ mod a { use mac; use mini_mac::ClippyMiniMacroTest; use mini_mac; - use mac::{inner::foofoo, inner::try_err}; + use mac::{inner::mut_mut, inner::try_err}; use mac::inner; use mac::inner::nested::string_add; use mac::inner::nested; @@ -36,7 +36,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index b34817cc3b2..b1a28733294 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -36,7 +36,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index 61843124ccd..68d558dede0 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -16,7 +16,7 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:23:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:19:5 diff --git a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs index 8a1b05da9ef..5aac5af26db 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs @@ -39,7 +39,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed index b7e46a4a8cc..5cc4a43af7e 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.fixed +++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed @@ -107,4 +107,10 @@ mod issue_5765 { } } +pub async fn issue_10450() -> i32 { 42 } + +pub(crate) async fn issue_10450_2() -> i32 { 42 } + +pub(self) async fn issue_10450_3() -> i32 { 42 } + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs index b05429da662..ba504b8a823 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.rs +++ b/src/tools/clippy/tests/ui/manual_async_fn.rs @@ -127,4 +127,16 @@ mod issue_5765 { } } +pub fn issue_10450() -> impl Future<Output = i32> { + async { 42 } +} + +pub(crate) fn issue_10450_2() -> impl Future<Output = i32> { + async { 42 } +} + +pub(self) fn issue_10450_3() -> impl Future<Output = i32> { + async { 42 } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr index 0a903ed6fd4..f5ee3eb7ccc 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.stderr +++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr @@ -161,5 +161,50 @@ help: move the body of the async block to the enclosing function LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { 42 } | ~~~~~~ -error: aborting due to 10 previous errors +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:130:1 + | +LL | pub fn issue_10450() -> impl Future<Output = i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub async fn issue_10450() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub fn issue_10450() -> impl Future<Output = i32> { 42 } + | ~~~~~~ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:134:1 + | +LL | pub(crate) fn issue_10450_2() -> impl Future<Output = i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub(crate) async fn issue_10450_2() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub(crate) fn issue_10450_2() -> impl Future<Output = i32> { 42 } + | ~~~~~~ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:138:1 + | +LL | pub(self) fn issue_10450_3() -> impl Future<Output = i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub(self) async fn issue_10450_3() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub(self) fn issue_10450_3() -> impl Future<Output = i32> { 42 } + | ~~~~~~ + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/manual_clamp.rs b/src/tools/clippy/tests/ui/manual_clamp.rs index f7902e6fd53..cdfd8e4c3fe 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.rs +++ b/src/tools/clippy/tests/ui/manual_clamp.rs @@ -326,3 +326,22 @@ fn msrv_1_50() { input }; } + +const fn _const() { + let (input, min, max) = (0, -1, 2); + let _ = if input < min { + min + } else if input > max { + max + } else { + input + }; + + let mut x = input; + if max < x { + let x = max; + } + if min > x { + x = min; + } +} diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.fixed b/src/tools/clippy/tests/ui/manual_main_separator_str.fixed new file mode 100644 index 00000000000..50f46d6b355 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.fixed @@ -0,0 +1,39 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_main_separator_str)] + +use std::path::MAIN_SEPARATOR; + +fn len(s: &str) -> usize { + s.len() +} + +struct U<'a> { + f: &'a str, + g: &'a String, +} + +struct V<T> { + f: T, +} + +fn main() { + // Should lint + let _: &str = std::path::MAIN_SEPARATOR_STR; + let _ = len(std::path::MAIN_SEPARATOR_STR); + let _: Vec<u16> = std::path::MAIN_SEPARATOR_STR.encode_utf16().collect(); + + // Should lint for field `f` only + let _ = U { + f: std::path::MAIN_SEPARATOR_STR, + g: &MAIN_SEPARATOR.to_string(), + }; + + // Should not lint + let _: &String = &MAIN_SEPARATOR.to_string(); + let _ = &MAIN_SEPARATOR.to_string(); + let _ = V { + f: &MAIN_SEPARATOR.to_string(), + }; +} diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.rs b/src/tools/clippy/tests/ui/manual_main_separator_str.rs new file mode 100644 index 00000000000..2dbb9e66151 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.rs @@ -0,0 +1,39 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_main_separator_str)] + +use std::path::MAIN_SEPARATOR; + +fn len(s: &str) -> usize { + s.len() +} + +struct U<'a> { + f: &'a str, + g: &'a String, +} + +struct V<T> { + f: T, +} + +fn main() { + // Should lint + let _: &str = &MAIN_SEPARATOR.to_string(); + let _ = len(&MAIN_SEPARATOR.to_string()); + let _: Vec<u16> = MAIN_SEPARATOR.to_string().encode_utf16().collect(); + + // Should lint for field `f` only + let _ = U { + f: &MAIN_SEPARATOR.to_string(), + g: &MAIN_SEPARATOR.to_string(), + }; + + // Should not lint + let _: &String = &MAIN_SEPARATOR.to_string(); + let _ = &MAIN_SEPARATOR.to_string(); + let _ = V { + f: &MAIN_SEPARATOR.to_string(), + }; +} diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.stderr b/src/tools/clippy/tests/ui/manual_main_separator_str.stderr new file mode 100644 index 00000000000..e6cefde66a7 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.stderr @@ -0,0 +1,28 @@ +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:23:19 + | +LL | let _: &str = &MAIN_SEPARATOR.to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + | + = note: `-D clippy::manual-main-separator-str` implied by `-D warnings` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:24:17 + | +LL | let _ = len(&MAIN_SEPARATOR.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:25:23 + | +LL | let _: Vec<u16> = MAIN_SEPARATOR.to_string().encode_utf16().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:29:12 + | +LL | f: &MAIN_SEPARATOR.to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed index 6916a284a20..1f6df1b0a86 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed @@ -1,19 +1,13 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] -#[macro_use] -extern crate macro_rules; - -macro_rules! internal_rem_euclid { - () => { - let value: i32 = 5; - let _: i32 = value.rem_euclid(4); - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let value: i32 = 5; @@ -39,10 +33,16 @@ fn main() { let _: i32 = ((4 % value) + 4) % 4; // Lint in internal macros - internal_rem_euclid!(); + inline!( + let value: i32 = 5; + let _: i32 = value.rem_euclid(4); + ); // Do not lint in external macros - manual_rem_euclid!(); + external!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); } // Should lint for params too diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.rs b/src/tools/clippy/tests/ui/manual_rem_euclid.rs index 412dbddb426..b275e8a38d2 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.rs +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.rs @@ -1,19 +1,13 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] -#[macro_use] -extern crate macro_rules; - -macro_rules! internal_rem_euclid { - () => { - let value: i32 = 5; - let _: i32 = ((value % 4) + 4) % 4; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let value: i32 = 5; @@ -39,10 +33,16 @@ fn main() { let _: i32 = ((4 % value) + 4) % 4; // Lint in internal macros - internal_rem_euclid!(); + inline!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); // Do not lint in external macros - manual_rem_euclid!(); + external!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); } // Should lint for params too diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr index 6d06654638b..a43707f89c4 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr @@ -1,5 +1,5 @@ error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:20:18 + --> $DIR/manual_rem_euclid.rs:14:18 | LL | let _: i32 = ((value % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` @@ -7,39 +7,36 @@ LL | let _: i32 = ((value % 4) + 4) % 4; = note: `-D clippy::manual-rem-euclid` implied by `-D warnings` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:21:18 + --> $DIR/manual_rem_euclid.rs:15:18 | LL | let _: i32 = (4 + (value % 4)) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:22:18 + --> $DIR/manual_rem_euclid.rs:16:18 | LL | let _: i32 = (value % 4 + 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:23:18 + --> $DIR/manual_rem_euclid.rs:17:18 | LL | let _: i32 = (4 + value % 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:24:22 + --> $DIR/manual_rem_euclid.rs:18:22 | LL | let _: i32 = 1 + (4 + value % 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:13:22 + --> $DIR/manual_rem_euclid.rs:38:22 | LL | let _: i32 = ((value % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` -... -LL | internal_rem_euclid!(); - | ---------------------- in this macro invocation | - = note: this error originates in the macro `internal_rem_euclid` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: manual `rem_euclid` implementation --> $DIR/manual_rem_euclid.rs:50:5 diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed index 6cfb6661a03..201301cc9b7 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding.fixed @@ -1,7 +1,12 @@ // run-rustfix #![warn(clippy::match_single_binding)] -#![allow(unused_variables)] -#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)] +#![allow( + unused, + clippy::let_unit_value, + clippy::no_effect, + clippy::toplevel_ref_arg, + clippy::uninlined_format_args +)] struct Point { x: i32, @@ -109,10 +114,9 @@ fn main() { // Lint let x = 1; - println!("Not an array index start"); + println!("Not an array index start") } -#[allow(dead_code)] fn issue_8723() { let (mut val, idx) = ("a b", 1); @@ -125,16 +129,15 @@ fn issue_8723() { let _ = val; } -#[allow(dead_code)] +fn side_effects() {} + fn issue_9575() { - fn side_effects() {} let _ = || { side_effects(); - println!("Needs curlies"); + println!("Needs curlies") }; } -#[allow(dead_code)] fn issue_9725(r: Option<u32>) { let x = r; match x { @@ -146,3 +149,25 @@ fn issue_9725(r: Option<u32>) { }, }; } + +fn issue_10447() -> usize { + (); + + let a = (); + + side_effects(); + + let b = side_effects(); + + println!("1"); + + let c = println!("1"); + + let in_expr = [ + (), + side_effects(), + println!("1"), + ]; + + 2 +} diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs index f188aeb5f2f..8b047b19ce9 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.rs +++ b/src/tools/clippy/tests/ui/match_single_binding.rs @@ -1,7 +1,12 @@ // run-rustfix #![warn(clippy::match_single_binding)] -#![allow(unused_variables)] -#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)] +#![allow( + unused, + clippy::let_unit_value, + clippy::no_effect, + clippy::toplevel_ref_arg, + clippy::uninlined_format_args +)] struct Point { x: i32, @@ -127,7 +132,6 @@ fn main() { } } -#[allow(dead_code)] fn issue_8723() { let (mut val, idx) = ("a b", 1); @@ -141,15 +145,14 @@ fn issue_8723() { let _ = val; } -#[allow(dead_code)] +fn side_effects() {} + fn issue_9575() { - fn side_effects() {} let _ = || match side_effects() { _ => println!("Needs curlies"), }; } -#[allow(dead_code)] fn issue_9725(r: Option<u32>) { match r { x => match x { @@ -162,3 +165,43 @@ fn issue_9725(r: Option<u32>) { }, }; } + +fn issue_10447() -> usize { + match 1 { + _ => (), + } + + let a = match 1 { + _ => (), + }; + + match 1 { + _ => side_effects(), + } + + let b = match 1 { + _ => side_effects(), + }; + + match 1 { + _ => println!("1"), + } + + let c = match 1 { + _ => println!("1"), + }; + + let in_expr = [ + match 1 { + _ => (), + }, + match 1 { + _ => side_effects(), + }, + match 1 { + _ => println!("1"), + }, + ]; + + 2 +} diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr index e960d64ad2b..9d16af76c6a 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding.stderr @@ -1,5 +1,5 @@ error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:28:5 + --> $DIR/match_single_binding.rs:33:5 | LL | / match (a, b, c) { LL | | (x, y, z) => { @@ -18,7 +18,7 @@ LL + } | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:34:5 + --> $DIR/match_single_binding.rs:39:5 | LL | / match (a, b, c) { LL | | (x, y, z) => println!("{} {} {}", x, y, z), @@ -32,7 +32,7 @@ LL + println!("{} {} {}", x, y, z); | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:51:5 + --> $DIR/match_single_binding.rs:56:5 | LL | / match a { LL | | _ => println!("whatever"), @@ -40,7 +40,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("whatever");` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:55:5 + --> $DIR/match_single_binding.rs:60:5 | LL | / match a { LL | | _ => { @@ -59,7 +59,7 @@ LL + } | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:62:5 + --> $DIR/match_single_binding.rs:67:5 | LL | / match a { LL | | _ => { @@ -81,7 +81,7 @@ LL + } | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:72:5 + --> $DIR/match_single_binding.rs:77:5 | LL | / match p { LL | | Point { x, y } => println!("Coords: ({}, {})", x, y), @@ -95,7 +95,7 @@ LL + println!("Coords: ({}, {})", x, y); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:76:5 + --> $DIR/match_single_binding.rs:81:5 | LL | / match p { LL | | Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1), @@ -109,7 +109,7 @@ LL + println!("Coords: ({}, {})", x1, y1); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:81:5 + --> $DIR/match_single_binding.rs:86:5 | LL | / match x { LL | | ref r => println!("Got a reference to {}", r), @@ -123,7 +123,7 @@ LL + println!("Got a reference to {}", r); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:86:5 + --> $DIR/match_single_binding.rs:91:5 | LL | / match x { LL | | ref mut mr => println!("Got a mutable reference to {}", mr), @@ -137,7 +137,7 @@ LL + println!("Got a mutable reference to {}", mr); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:90:5 + --> $DIR/match_single_binding.rs:95:5 | LL | / let product = match coords() { LL | | Point { x, y } => x * y, @@ -151,7 +151,7 @@ LL + let product = x * y; | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:98:18 + --> $DIR/match_single_binding.rs:103:18 | LL | .map(|i| match i.unwrap() { | __________________^ @@ -168,16 +168,16 @@ LL ~ }) | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:124:5 + --> $DIR/match_single_binding.rs:129:5 | LL | / match x { LL | | // => LL | | _ => println!("Not an array index start"), LL | | } - | |_____^ help: consider using the match body instead: `println!("Not an array index start");` + | |_____^ help: consider using the match body instead: `println!("Not an array index start")` error: this assignment could be simplified - --> $DIR/match_single_binding.rs:134:5 + --> $DIR/match_single_binding.rs:138:5 | LL | / val = match val.split_at(idx) { LL | | (pre, suf) => { @@ -197,7 +197,7 @@ LL ~ }; | error: this match could be replaced by its scrutinee and body - --> $DIR/match_single_binding.rs:147:16 + --> $DIR/match_single_binding.rs:151:16 | LL | let _ = || match side_effects() { | ________________^ @@ -209,12 +209,12 @@ help: consider using the scrutinee and body instead | LL ~ let _ = || { LL + side_effects(); -LL + println!("Needs curlies"); +LL + println!("Needs curlies") LL ~ }; | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:154:5 + --> $DIR/match_single_binding.rs:157:5 | LL | / match r { LL | | x => match x { @@ -238,5 +238,80 @@ LL + }, LL ~ }; | -error: aborting due to 15 previous errors +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:170:5 + | +LL | / match 1 { +LL | | _ => (), +LL | | } + | |_____^ help: consider using the match body instead: `();` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:174:13 + | +LL | let a = match 1 { + | _____________^ +LL | | _ => (), +LL | | }; + | |_____^ help: consider using the match body instead: `()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:178:5 + | +LL | / match 1 { +LL | | _ => side_effects(), +LL | | } + | |_____^ help: consider using the match body instead: `side_effects();` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:182:13 + | +LL | let b = match 1 { + | _____________^ +LL | | _ => side_effects(), +LL | | }; + | |_____^ help: consider using the match body instead: `side_effects()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:186:5 + | +LL | / match 1 { +LL | | _ => println!("1"), +LL | | } + | |_____^ help: consider using the match body instead: `println!("1");` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:190:13 + | +LL | let c = match 1 { + | _____________^ +LL | | _ => println!("1"), +LL | | }; + | |_____^ help: consider using the match body instead: `println!("1")` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:195:9 + | +LL | / match 1 { +LL | | _ => (), +LL | | }, + | |_________^ help: consider using the match body instead: `()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:198:9 + | +LL | / match 1 { +LL | | _ => side_effects(), +LL | | }, + | |_________^ help: consider using the match body instead: `side_effects()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:201:9 + | +LL | / match 1 { +LL | | _ => println!("1"), +LL | | }, + | |_________^ help: consider using the match body instead: `println!("1")` + +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed index 6a7db67e311..e3cf56a4293 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed @@ -30,7 +30,7 @@ fn main() { #[rustfmt::skip] Some((first, _second)) => { let (a, b) = get_tup(); - println!("a {:?} and b {:?}", a, b); + println!("a {:?} and b {:?}", a, b) }, None => println!("nothing"), } @@ -49,5 +49,5 @@ fn main() { 0 => 1, _ => 2, }; - println!("Single branch"); + println!("Single branch") } diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr index 22bf7d8be4a..e180b93e76d 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr @@ -27,7 +27,7 @@ LL | | } help: consider using a `let` statement | LL ~ let (a, b) = get_tup(); -LL + println!("a {:?} and b {:?}", a, b); +LL + println!("a {:?} and b {:?}", a, b) | error: this match could be replaced by its scrutinee and body @@ -61,7 +61,7 @@ LL ~ match x { LL + 0 => 1, LL + _ => 2, LL + }; -LL + println!("Single branch"); +LL + println!("Single branch") | error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/mem_replace_macro.rs b/src/tools/clippy/tests/ui/mem_replace_macro.rs index 0c09344b80d..3932e7d00c1 100644 --- a/src/tools/clippy/tests/ui/mem_replace_macro.rs +++ b/src/tools/clippy/tests/ui/mem_replace_macro.rs @@ -1,21 +1,12 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::mem_replace_with_default)] -#[macro_use] -extern crate macro_rules; - -macro_rules! take { - ($s:expr) => { - std::mem::replace($s, Default::default()) - }; -} - -fn replace_with_default() { - let s = &mut String::from("foo"); - take!(s); - take_external!(s); -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { - replace_with_default(); + let s = &mut String::from("foo"); + inline!(std::mem::replace($s, Default::default())); + external!(std::mem::replace($s, Default::default())); } diff --git a/src/tools/clippy/tests/ui/mem_replace_macro.stderr b/src/tools/clippy/tests/ui/mem_replace_macro.stderr index dd69ab8b5ef..35dda93da3d 100644 --- a/src/tools/clippy/tests/ui/mem_replace_macro.stderr +++ b/src/tools/clippy/tests/ui/mem_replace_macro.stderr @@ -1,14 +1,11 @@ error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> $DIR/mem_replace_macro.rs:9:9 + --> $DIR/mem_replace_macro.rs:10:13 | -LL | std::mem::replace($s, Default::default()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | take!(s); - | -------- in this macro invocation +LL | inline!(std::mem::replace($s, Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` - = note: this error originates in the macro `take` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs index 75cace18167..e6f88c6e622 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -3,15 +3,15 @@ //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. // aux-build:helper.rs -// aux-build:../../auxiliary/proc_macro_with_span.rs +// aux-build:../../auxiliary/proc_macros.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] extern crate helper; -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; struct Game; diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs index 590ad63c90b..5752048949c 100644 --- a/src/tools/clippy/tests/ui/missing_doc.rs +++ b/src/tools/clippy/tests/ui/missing_doc.rs @@ -1,5 +1,5 @@ // needs-asm-support -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the @@ -8,9 +8,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::arch::global_asm; type Typedef = String; diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.rs b/src/tools/clippy/tests/ui/missing_doc_impl.rs index 0396d1193ff..e2d49b0907d 100644 --- a/src/tools/clippy/tests/ui/missing_doc_impl.rs +++ b/src/tools/clippy/tests/ui/missing_doc_impl.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] @@ -7,8 +7,8 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Foo { a: isize, diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed index becb9562a84..9a47d7c56ed 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![allow( dead_code, @@ -10,8 +10,8 @@ clippy::unusual_byte_groupings )] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; fn main() { let fail14 = 2_i32; diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs index ee841bcd7e4..04261cba55a 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![allow( dead_code, @@ -10,8 +10,8 @@ clippy::unusual_byte_groupings )] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; fn main() { let fail14 = 2_32; diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs index 5073685c9f0..9082f1675a8 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,12 +1,12 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::drop_copy)] #![warn(clippy::multiple_unsafe_ops_per_block)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; use core::arch::asm; @@ -113,7 +113,10 @@ unsafe fn read_char_good(ptr: *const u8) -> char { // no lint fn issue10259() { - unsafe_macro!(); + external!(unsafe { + *core::ptr::null::<()>(); + *core::ptr::null::<()>(); + }); } fn _fn_ptr(x: unsafe fn()) { diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr index e0c1d3801f7..badc284ec42 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -126,7 +126,7 @@ LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:120:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:123:5 | LL | / unsafe { LL | | x(); @@ -135,18 +135,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:121:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:124:9 | LL | x(); | ^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:122:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:125:9 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:131:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:134:9 | LL | / unsafe { LL | | T::X(); @@ -155,18 +155,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:132:13 + --> $DIR/multiple_unsafe_ops_per_block.rs:135:13 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:133:13 + --> $DIR/multiple_unsafe_ops_per_block.rs:136:13 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:141:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:144:5 | LL | / unsafe { LL | | x.0(); @@ -175,12 +175,12 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:142:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:145:9 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:143:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:146:9 | LL | x.0(); | ^^^^^ diff --git a/src/tools/clippy/tests/ui/must_use_unit.fixed b/src/tools/clippy/tests/ui/must_use_unit.fixed index 6c9aa434ac0..b7d375ff80e 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.fixed +++ b/src/tools/clippy/tests/ui/must_use_unit.fixed @@ -1,11 +1,11 @@ //run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; pub fn must_use_default() {} @@ -22,5 +22,8 @@ fn main() { must_use_with_note(); // We should not lint in external macros - must_use_unit!(); + external!( + #[must_use] + fn foo() {} + ); } diff --git a/src/tools/clippy/tests/ui/must_use_unit.rs b/src/tools/clippy/tests/ui/must_use_unit.rs index 8a395dc284d..74d6b4ca865 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.rs +++ b/src/tools/clippy/tests/ui/must_use_unit.rs @@ -1,11 +1,11 @@ //run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; #[must_use] pub fn must_use_default() {} @@ -22,5 +22,8 @@ fn main() { must_use_with_note(); // We should not lint in external macros - must_use_unit!(); + external!( + #[must_use] + fn foo() {} + ); } diff --git a/src/tools/clippy/tests/ui/mut_mut.rs b/src/tools/clippy/tests/ui/mut_mut.rs index ee3a856566c..06bb085442a 100644 --- a/src/tools/clippy/tests/ui/mut_mut.rs +++ b/src/tools/clippy/tests/ui/mut_mut.rs @@ -1,10 +1,10 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::mut_mut)] #![allow(unused)] #![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn fun(x: &mut &mut u32) -> bool { **x > 0 @@ -21,6 +21,7 @@ macro_rules! mut_ptr { } #[allow(unused_mut, unused_variables)] +#[inline_macros] fn main() { let mut x = &mut &mut 1u32; { @@ -37,7 +38,7 @@ fn main() { ***y + **x; } - let mut z = mut_ptr!(&mut 3u32); + let mut z = inline!(&mut $(&mut 3u32)); } fn issue939() { @@ -55,7 +56,7 @@ fn issue939() { fn issue6922() { // do not lint from an external macro - mut_mut!(); + external!(let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;); } mod issue9035 { diff --git a/src/tools/clippy/tests/ui/mut_mut.stderr b/src/tools/clippy/tests/ui/mut_mut.stderr index 6820a85aa54..93b857eb207 100644 --- a/src/tools/clippy/tests/ui/mut_mut.stderr +++ b/src/tools/clippy/tests/ui/mut_mut.stderr @@ -7,54 +7,51 @@ LL | fn fun(x: &mut &mut u32) -> bool { = note: `-D clippy::mut-mut` implied by `-D warnings` error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:25:17 + --> $DIR/mut_mut.rs:26:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:19:9 + --> $DIR/mut_mut.rs:41:25 | -LL | &mut $p - | ^^^^^^^ -... -LL | let mut z = mut_ptr!(&mut 3u32); - | ------------------- in this macro invocation +LL | let mut z = inline!(&mut $(&mut 3u32)); + | ^ | - = note: this error originates in the macro `mut_ptr` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this expression mutably borrows a mutable reference. Consider reborrowing - --> $DIR/mut_mut.rs:27:21 + --> $DIR/mut_mut.rs:28:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:32 + --> $DIR/mut_mut.rs:32:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:16 + --> $DIR/mut_mut.rs:32:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:37 + --> $DIR/mut_mut.rs:37:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:16 + --> $DIR/mut_mut.rs:37:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:21 + --> $DIR/mut_mut.rs:37:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index 17f2227ba91..86d899bb46c 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( @@ -10,6 +11,8 @@ clippy::uninlined_format_args )] +extern crate proc_macros; + use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -138,6 +141,7 @@ const fn in_const() -> &'static str { a } +#[proc_macros::inline_macros] fn does_not_lint() { let z; if false { @@ -195,35 +199,27 @@ fn does_not_lint() { } y = 3; - macro_rules! assign { - ($i:ident) => { - $i = 1; - }; - } let x; - assign!(x); + inline!($x = 1;); let x; if true { - assign!(x); + inline!($x = 1;); } else { x = 2; } - macro_rules! in_macro { - () => { - let x; - x = 1; + inline!({ + let x; + x = 1; - let x; - if true { - x = 1; - } else { - x = 2; - } - }; - } - in_macro!(); + let x; + if true { + x = 1; + } else { + x = 2; + } + }); // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613 let x; diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index d84457a2987..969afb38edf 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( @@ -10,6 +11,8 @@ clippy::uninlined_format_args )] +extern crate proc_macros; + use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -138,6 +141,7 @@ const fn in_const() -> &'static str { a } +#[proc_macros::inline_macros] fn does_not_lint() { let z; if false { @@ -195,35 +199,27 @@ fn does_not_lint() { } y = 3; - macro_rules! assign { - ($i:ident) => { - $i = 1; - }; - } let x; - assign!(x); + inline!($x = 1;); let x; if true { - assign!(x); + inline!($x = 1;); } else { x = 2; } - macro_rules! in_macro { - () => { - let x; - x = 1; + inline!({ + let x; + x = 1; - let x; - if true { - x = 1; - } else { - x = 2; - } - }; - } - in_macro!(); + let x; + if true { + x = 1; + } else { + x = 2; + } + }); // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613 let x; diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index 0a256fb4a13..eff782f8bf1 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init.stderr @@ -1,5 +1,5 @@ error: unneeded late initialization - --> $DIR/needless_late_init.rs:24:5 + --> $DIR/needless_late_init.rs:27:5 | LL | let a; | ^^^^^^ created here @@ -13,7 +13,7 @@ LL | let a = "zero"; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:27:5 + --> $DIR/needless_late_init.rs:30:5 | LL | let b; | ^^^^^^ created here @@ -27,7 +27,7 @@ LL | let b = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:28:5 + --> $DIR/needless_late_init.rs:31:5 | LL | let c; | ^^^^^^ created here @@ -41,7 +41,7 @@ LL | let c = 2; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:32:5 + --> $DIR/needless_late_init.rs:35:5 | LL | let d: usize; | ^^^^^^^^^^^^^ created here @@ -54,7 +54,7 @@ LL | let d: usize = 1; | ~~~~~~~~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:35:5 + --> $DIR/needless_late_init.rs:38:5 | LL | let e; | ^^^^^^ created here @@ -67,7 +67,7 @@ LL | let e = format!("{}", d); | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:40:5 + --> $DIR/needless_late_init.rs:43:5 | LL | let a; | ^^^^^^ @@ -88,7 +88,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:49:5 + --> $DIR/needless_late_init.rs:52:5 | LL | let b; | ^^^^^^ @@ -109,7 +109,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:56:5 + --> $DIR/needless_late_init.rs:59:5 | LL | let d; | ^^^^^^ @@ -130,7 +130,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:64:5 + --> $DIR/needless_late_init.rs:67:5 | LL | let e; | ^^^^^^ @@ -151,7 +151,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:71:5 + --> $DIR/needless_late_init.rs:74:5 | LL | let f; | ^^^^^^ @@ -167,7 +167,7 @@ LL + 1 => "three", | error: unneeded late initialization - --> $DIR/needless_late_init.rs:77:5 + --> $DIR/needless_late_init.rs:80:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:85:5 + --> $DIR/needless_late_init.rs:88:5 | LL | let x; | ^^^^^^ created here @@ -201,7 +201,7 @@ LL | let x = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:89:5 + --> $DIR/needless_late_init.rs:92:5 | LL | let x; | ^^^^^^ created here @@ -215,7 +215,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:93:5 + --> $DIR/needless_late_init.rs:96:5 | LL | let x; | ^^^^^^ created here @@ -229,7 +229,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:112:5 + --> $DIR/needless_late_init.rs:115:5 | LL | let a; | ^^^^^^ @@ -250,7 +250,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:129:5 + --> $DIR/needless_late_init.rs:132:5 | LL | let a; | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed index f0f1f9298ac..e6ead69d148 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( @@ -12,8 +12,8 @@ clippy::get_first )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::inline_macros; fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} @@ -502,30 +502,29 @@ mod pr_9743_output_lifetime_checks { } } +#[inline_macros] mod in_macro { - macro_rules! local_one_input_macro { - () => { - fn one_input(x: &u8) -> &u8 { - unimplemented!() - } - }; - } + use proc_macros::external; // lint local macro expands to function with needless lifetimes - local_one_input_macro!(); + inline! { + fn one_input(x: &u8) -> &u8 { + unimplemented!() + } + } // no lint on external macro - macro_rules::needless_lifetime!(); - - macro_rules! expanded_lifetime { - ($l:lifetime) => { - fn f<$l>(arg: &$l str) -> &$l str { - arg - } + external! { + fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() } } - expanded_lifetime!('a); + inline! { + fn f<$'a>(arg: &$'a str) -> &$'a str { + arg + } + } } mod issue5787 { diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index ddfd1043003..06eb430506f 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( @@ -12,8 +12,8 @@ clippy::get_first )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::inline_macros; fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} @@ -502,30 +502,29 @@ mod pr_9743_output_lifetime_checks { } } +#[inline_macros] mod in_macro { - macro_rules! local_one_input_macro { - () => { - fn one_input<'a>(x: &'a u8) -> &'a u8 { - unimplemented!() - } - }; - } + use proc_macros::external; // lint local macro expands to function with needless lifetimes - local_one_input_macro!(); + inline! { + fn one_input<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + } // no lint on external macro - macro_rules::needless_lifetime!(); - - macro_rules! expanded_lifetime { - ($l:lifetime) => { - fn f<$l>(arg: &$l str) -> &$l str { - arg - } + external! { + fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() } } - expanded_lifetime!('a); + inline! { + fn f<$'a>(arg: &$'a str) -> &$'a str { + arg + } + } } mod issue5787 { diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr index 4e3c8f20d8c..86acc4e0046 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr @@ -540,19 +540,16 @@ LL + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:508:13 + --> $DIR/needless_lifetimes.rs:511:9 | -LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | local_one_input_macro!(); - | ------------------------ in this macro invocation +LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in the macro `local_one_input_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) help: elide the lifetimes | -LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { -LL + fn one_input(x: &u8) -> &u8 { +LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { +LL + fn one_input(x: &u8) -> &u8 { | error: aborting due to 46 previous errors diff --git a/src/tools/clippy/tests/ui/needless_update.rs b/src/tools/clippy/tests/ui/needless_update.rs index b93ff048a62..4e8517cad10 100644 --- a/src/tools/clippy/tests/ui/needless_update.rs +++ b/src/tools/clippy/tests/ui/needless_update.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_update)] -#![allow(clippy::no_effect)] +#![allow(clippy::no_effect, clippy::unnecessary_struct_initialization)] struct S { pub a: i32, diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index ec8a5aa28c5..1e42e1fbabf 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -1,7 +1,12 @@ #![feature(fn_traits, unboxed_closures)] #![warn(clippy::no_effect_underscore_binding)] #![allow(dead_code, path_statements)] -#![allow(clippy::deref_addrof, clippy::redundant_field_names, clippy::uninlined_format_args)] +#![allow( + clippy::deref_addrof, + clippy::redundant_field_names, + clippy::uninlined_format_args, + clippy::unnecessary_struct_initialization +)] struct Unit; struct Tuple(i32); diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr index 92f6dbfbdba..f10f2bcf2a8 100644 --- a/src/tools/clippy/tests/ui/no_effect.stderr +++ b/src/tools/clippy/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> $DIR/no_effect.rs:92:5 + --> $DIR/no_effect.rs:97:5 | LL | 0; | ^^ @@ -7,151 +7,151 @@ LL | 0; = note: `-D clippy::no-effect` implied by `-D warnings` error: statement with no effect - --> $DIR/no_effect.rs:93:5 + --> $DIR/no_effect.rs:98:5 | LL | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:94:5 + --> $DIR/no_effect.rs:99:5 | LL | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:95:5 + --> $DIR/no_effect.rs:100:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:96:5 + --> $DIR/no_effect.rs:101:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:97:5 + --> $DIR/no_effect.rs:102:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:98:5 + --> $DIR/no_effect.rs:103:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:99:5 + --> $DIR/no_effect.rs:104:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:100:5 + --> $DIR/no_effect.rs:105:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:106:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:102:5 + --> $DIR/no_effect.rs:107:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:103:5 + --> $DIR/no_effect.rs:108:5 | LL | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:104:5 + --> $DIR/no_effect.rs:109:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:105:5 + --> $DIR/no_effect.rs:110:5 | LL | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:106:5 + --> $DIR/no_effect.rs:111:5 | LL | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:107:5 + --> $DIR/no_effect.rs:112:5 | LL | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:108:5 + --> $DIR/no_effect.rs:113:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:109:5 + --> $DIR/no_effect.rs:114:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:110:5 + --> $DIR/no_effect.rs:115:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:111:5 + --> $DIR/no_effect.rs:116:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:112:5 + --> $DIR/no_effect.rs:117:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:113:5 + --> $DIR/no_effect.rs:118:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:114:5 + --> $DIR/no_effect.rs:119:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:116:5 + --> $DIR/no_effect.rs:121:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:118:5 + --> $DIR/no_effect.rs:123:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:119:5 + --> $DIR/no_effect.rs:124:5 | LL | let _unused = 1; | ^^^^^^^^^^^^^^^^ @@ -159,19 +159,19 @@ LL | let _unused = 1; = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:120:5 + --> $DIR/no_effect.rs:125:5 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:121:5 + --> $DIR/no_effect.rs:126:5 | LL | let _duck = Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:122:5 + --> $DIR/no_effect.rs:127:5 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed deleted file mode 100644 index d18dec22a8b..00000000000 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed +++ /dev/null @@ -1,48 +0,0 @@ -// run-rustfix - -#![allow(unused)] -#![warn(clippy::no_mangle_with_rust_abi)] - -#[no_mangle] -extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} - -/// # Safety -/// This function shouldn't be called unless the horsemen are ready -#[no_mangle] -pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} - -/// # Safety -/// This function shouldn't be called unless the horsemen are ready -#[no_mangle] -unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( - arg_one: u32, - arg_two: usize, -) -> u32 { - 0 -} - -// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"` -#[no_mangle] -#[rustfmt::skip] -extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {} - -fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {} - -extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {} - -extern "C" { - fn c_abi_in_block(arg_one: u32, arg_two: usize); -} - -fn main() { - // test code goes here -} diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs index 481e1b6d961..b32e721110e 100644 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![allow(unused)] #![warn(clippy::no_mangle_with_rust_abi)] diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr index 71517d31809..da5d31d8f2d 100644 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr +++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr @@ -1,31 +1,66 @@ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:7:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:5:1 | LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings` +help: set an ABI + | +LL | extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:10:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:8:1 | LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:15:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:13:1 | LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:20:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:18:1 | LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:23:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:21:1 | LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( LL | | arg_one: u32, @@ -33,13 +68,14 @@ LL | | arg_two: usize, LL | | ) -> u32 { | |________^ | -help: try +help: set an ABI | -LL + extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( -LL + arg_one: u32, -LL + arg_two: usize, -LL ~ ) -> u32 { +LL | extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( + | ++++++++++ +help: or explicitly set the default | +LL | extern "Rust" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( + | +++++++++++++ error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs index e9b4367ca65..3b5a374b4a7 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs @@ -63,3 +63,32 @@ fn issue9428() { println!("foo"); } } + +fn issue_10523() { + macro_rules! a { + ($v:expr) => { + $v.is_some() + }; + } + let x: Option<u32> = None; + if !a!(x) {} +} + +fn issue_10523_1() { + macro_rules! a { + ($v:expr) => { + !$v.is_some() + }; + } + let x: Option<u32> = None; + if a!(x) {} +} + +fn issue_10523_2() { + macro_rules! a { + () => { + !None::<u32>.is_some() + }; + } + if a!() {} +} diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs index 0141fb7856d..9a56cf40d8a 100644 --- a/src/tools/clippy/tests/ui/option_env_unwrap.rs +++ b/src/tools/clippy/tests/ui/option_env_unwrap.rs @@ -1,24 +1,16 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::option_env_unwrap)] #![allow(clippy::map_flatten)] -#[macro_use] -extern crate macro_rules; - -macro_rules! option_env_unwrap { - ($env: expr) => { - option_env!($env).unwrap() - }; - ($env: expr, $message: expr) => { - option_env!($env).expect($message) - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let _ = option_env!("PATH").unwrap(); let _ = option_env!("PATH").expect("environment variable PATH isn't set"); - let _ = option_env_unwrap!("PATH"); - let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set"); - let _ = option_env_unwrap_external!("PATH"); - let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set"); + let _ = inline!(option_env!($"PATH").unwrap()); + let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + let _ = external!(option_env!($"PATH").unwrap()); + let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); } diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr index bc188a07e9e..7bba62686ee 100644 --- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr +++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr @@ -1,5 +1,5 @@ error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:18:13 + --> $DIR/option_env_unwrap.rs:10:13 | LL | let _ = option_env!("PATH").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = option_env!("PATH").unwrap(); = note: `-D clippy::option-env-unwrap` implied by `-D warnings` error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:19:13 + --> $DIR/option_env_unwrap.rs:11:13 | LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,46 +16,40 @@ LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set = help: consider using the `env!` macro instead error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:10:9 + --> $DIR/option_env_unwrap.rs:12:21 | -LL | option_env!($env).unwrap() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | let _ = option_env_unwrap!("PATH"); - | -------------------------- in this macro invocation +LL | let _ = inline!(option_env!($"PATH").unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:13:9 + --> $DIR/option_env_unwrap.rs:13:21 | -LL | option_env!($env).expect($message) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set"); - | ----------------------------------------------------------------- in this macro invocation +LL | let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:22:13 + --> $DIR/option_env_unwrap.rs:14:13 | -LL | let _ = option_env_unwrap_external!("PATH"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ = external!(option_env!($"PATH").unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:23:13 + --> $DIR/option_env_unwrap.rs:15:13 | -LL | let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed index df36a9b842b..ee7b998a0b2 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed @@ -1,16 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] -extern crate macro_rules; - -macro_rules! cast_it { - ($ptr: ident) => { - $ptr.cast::<i32>() - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; @@ -38,10 +34,10 @@ fn main() { let _: *mut i32 = mut_ptr.cast(); // Make sure the lint is triggered inside a macro - let _ = cast_it!(ptr); + let _ = inline!($ptr.cast::<i32>()); // Do not lint inside macros from external crates - let _ = macro_rules::ptr_as_ptr_cast!(ptr); + let _ = external!($ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs index 302c66462d9..c88329ce4ec 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs @@ -1,16 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] -extern crate macro_rules; - -macro_rules! cast_it { - ($ptr: ident) => { - $ptr as *const i32 - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; @@ -38,10 +34,10 @@ fn main() { let _: *mut i32 = mut_ptr as _; // Make sure the lint is triggered inside a macro - let _ = cast_it!(ptr); + let _ = inline!($ptr as *const i32); // Do not lint inside macros from external crates - let _ = macro_rules::ptr_as_ptr_cast!(ptr); + let _ = external!($ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index a68e1cab6d3..78d733994ac 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -1,5 +1,5 @@ error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:18:13 + --> $DIR/ptr_as_ptr.rs:14:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()` @@ -7,48 +7,45 @@ LL | let _ = ptr as *const i32; = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:19:13 + --> $DIR/ptr_as_ptr.rs:15:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:24:17 + --> $DIR/ptr_as_ptr.rs:20:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:37:25 + --> $DIR/ptr_as_ptr.rs:33:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:38:23 + --> $DIR/ptr_as_ptr.rs:34:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:10:9 + --> $DIR/ptr_as_ptr.rs:37:21 | -LL | $ptr as *const i32 - | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()` -... -LL | let _ = cast_it!(ptr); - | ------------- in this macro invocation +LL | let _ = inline!($ptr as *const i32); + | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()` | - = note: this error originates in the macro `cast_it` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:62:13 + --> $DIR/ptr_as_ptr.rs:58:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:63:13 + --> $DIR/ptr_as_ptr.rs:59:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()` diff --git a/src/tools/clippy/tests/ui/redundant_async_block.fixed b/src/tools/clippy/tests/ui/redundant_async_block.fixed index 5f9931df45e..d26b7a332cb 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.fixed +++ b/src/tools/clippy/tests/ui/redundant_async_block.fixed @@ -3,6 +3,8 @@ #![allow(unused)] #![warn(clippy::redundant_async_block)] +use std::future::Future; + async fn func1(n: usize) -> usize { n + 1 } @@ -62,3 +64,48 @@ fn main() { let fut = async_await_parameter_in_macro!(func2()); let fut = async_await_in_macro!(std::convert::identity); } + +#[allow(clippy::let_and_return)] +fn capture_local() -> impl Future<Output = i32> { + // Lint + let fut = async { 17 }; + fut +} + +fn capture_local_closure(s: &str) -> impl Future<Output = &str> { + let f = move || std::future::ready(s); + // Do not lint: `f` would not live long enough + async move { f().await } +} + +#[allow(clippy::let_and_return)] +fn capture_arg(s: &str) -> impl Future<Output = &str> { + // Lint + let fut = async move { s }; + fut +} + +#[derive(Debug, Clone)] +struct F {} + +impl F { + async fn run(&self) {} +} + +pub async fn run() { + let f = F {}; + let c = f.clone(); + // Do not lint: `c` would not live long enough + spawn(async move { c.run().await }); + let _f = f; +} + +fn spawn<F: Future + 'static>(_: F) {} + +async fn work(_: &str) {} + +fn capture() { + let val = "Hello World".to_owned(); + // Do not lint: `val` would not live long enough + spawn(async { work(&{ val }).await }); +} diff --git a/src/tools/clippy/tests/ui/redundant_async_block.rs b/src/tools/clippy/tests/ui/redundant_async_block.rs index de3c9970c65..04726e62805 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.rs +++ b/src/tools/clippy/tests/ui/redundant_async_block.rs @@ -3,6 +3,8 @@ #![allow(unused)] #![warn(clippy::redundant_async_block)] +use std::future::Future; + async fn func1(n: usize) -> usize { n + 1 } @@ -62,3 +64,48 @@ fn main() { let fut = async_await_parameter_in_macro!(func2()); let fut = async_await_in_macro!(std::convert::identity); } + +#[allow(clippy::let_and_return)] +fn capture_local() -> impl Future<Output = i32> { + // Lint + let fut = async { 17 }; + async move { fut.await } +} + +fn capture_local_closure(s: &str) -> impl Future<Output = &str> { + let f = move || std::future::ready(s); + // Do not lint: `f` would not live long enough + async move { f().await } +} + +#[allow(clippy::let_and_return)] +fn capture_arg(s: &str) -> impl Future<Output = &str> { + // Lint + let fut = async move { s }; + async move { fut.await } +} + +#[derive(Debug, Clone)] +struct F {} + +impl F { + async fn run(&self) {} +} + +pub async fn run() { + let f = F {}; + let c = f.clone(); + // Do not lint: `c` would not live long enough + spawn(async move { c.run().await }); + let _f = f; +} + +fn spawn<F: Future + 'static>(_: F) {} + +async fn work(_: &str) {} + +fn capture() { + let val = "Hello World".to_owned(); + // Do not lint: `val` would not live long enough + spawn(async { work(&{ val }).await }); +} diff --git a/src/tools/clippy/tests/ui/redundant_async_block.stderr b/src/tools/clippy/tests/ui/redundant_async_block.stderr index b16d96dce84..1a1c1603e08 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.stderr +++ b/src/tools/clippy/tests/ui/redundant_async_block.stderr @@ -1,5 +1,5 @@ error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:13:13 + --> $DIR/redundant_async_block.rs:15:13 | LL | let x = async { f.await }; | ^^^^^^^^^^^^^^^^^ help: you can reduce it to: `f` @@ -7,22 +7,34 @@ LL | let x = async { f.await }; = note: `-D clippy::redundant-async-block` implied by `-D warnings` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:46:16 + --> $DIR/redundant_async_block.rs:48:16 | LL | let fut2 = async { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:49:16 + --> $DIR/redundant_async_block.rs:51:16 | LL | let fut2 = async move { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:51:15 + --> $DIR/redundant_async_block.rs:53:15 | LL | let fut = async { async { 42 }.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` -error: aborting due to 4 previous errors +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:72:5 + | +LL | async move { fut.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:85:5 + | +LL | async move { fut.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed index b88c5d0bec8..42348df4480 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed @@ -69,8 +69,8 @@ fn issue5504() { } fn try_result_opt() -> Result<i32, i32> { - while (r#try!(result_opt())).is_some() {} - if (r#try!(result_opt())).is_some() {} + while r#try!(result_opt()).is_some() {} + if r#try!(result_opt()).is_some() {} Ok(42) } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr index e6afe9eb78e..d6a46babb77 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr @@ -88,13 +88,13 @@ error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:84:19 | LL | while let Some(_) = r#try!(result_opt()) {} - | ----------^^^^^^^----------------------- help: try this: `while (r#try!(result_opt())).is_some()` + | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:85:16 | LL | if let Some(_) = r#try!(result_opt()) {} - | -------^^^^^^^----------------------- help: try this: `if (r#try!(result_opt())).is_some()` + | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:91:12 diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs index 5d03f77e932..3c86f41f3a6 100644 --- a/src/tools/clippy/tests/ui/single_match_else.rs +++ b/src/tools/clippy/tests/ui/single_match_else.rs @@ -1,9 +1,9 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::single_match_else)] #![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; enum ExprNode { ExprAddrOf, diff --git a/src/tools/clippy/tests/ui/string_add.rs b/src/tools/clippy/tests/ui/string_add.rs index 16673c01e63..20edbe31fa9 100644 --- a/src/tools/clippy/tests/ui/string_add.rs +++ b/src/tools/clippy/tests/ui/string_add.rs @@ -1,7 +1,7 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; #[warn(clippy::string_add)] #[allow(clippy::string_add_assign, unused)] @@ -22,5 +22,8 @@ fn main() { x = x + 1; assert_eq!(2, x); - string_add!(); + external!({ + let y = "".to_owned(); + let z = y + "..."; + }); } diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed index 04008c0d9b3..9703674d1a4 100644 --- a/src/tools/clippy/tests/ui/swap.fixed +++ b/src/tools/clippy/tests/ui/swap.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( @@ -8,7 +9,8 @@ redundant_semicolons, dead_code, unused_assignments, - unused_variables + unused_variables, + clippy::let_and_return )] struct Foo(u32); @@ -186,3 +188,14 @@ const fn issue_9864(mut u: u32) -> u32 { v = temp; u + v } + +#[macro_use] +extern crate macro_rules; + +const fn issue_10421(x: u32) -> u32 { + issue_10421!(); + let a = x; + let a = a; + let a = a; + a +} diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs index ef8a81c8341..a0228065e46 100644 --- a/src/tools/clippy/tests/ui/swap.rs +++ b/src/tools/clippy/tests/ui/swap.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( @@ -8,7 +9,8 @@ redundant_semicolons, dead_code, unused_assignments, - unused_variables + unused_variables, + clippy::let_and_return )] struct Foo(u32); @@ -215,3 +217,14 @@ const fn issue_9864(mut u: u32) -> u32 { v = temp; u + v } + +#[macro_use] +extern crate macro_rules; + +const fn issue_10421(x: u32) -> u32 { + issue_10421!(); + let a = x; + let a = a; + let a = a; + a +} diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr index 825c9261e19..0c246268499 100644 --- a/src/tools/clippy/tests/ui/swap.stderr +++ b/src/tools/clippy/tests/ui/swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:25:5 + --> $DIR/swap.rs:27:5 | LL | / let temp = bar.a; LL | | bar.a = bar.b; @@ -10,7 +10,7 @@ LL | | bar.b = temp; = note: `-D clippy::manual-swap` implied by `-D warnings` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:37:5 + --> $DIR/swap.rs:39:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -18,7 +18,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:46:5 + --> $DIR/swap.rs:48:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -26,7 +26,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:65:5 + --> $DIR/swap.rs:67:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -34,7 +34,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:76:5 + --> $DIR/swap.rs:78:5 | LL | / a ^= b; LL | | b ^= a; @@ -42,7 +42,7 @@ LL | | a ^= b; | |___________^ help: try: `std::mem::swap(&mut a, &mut b);` error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:84:5 + --> $DIR/swap.rs:86:5 | LL | / bar.a ^= bar.b; LL | | bar.b ^= bar.a; @@ -50,7 +50,7 @@ LL | | bar.a ^= bar.b; | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:92:5 + --> $DIR/swap.rs:94:5 | LL | / foo[0] ^= foo[1]; LL | | foo[1] ^= foo[0]; @@ -58,7 +58,7 @@ LL | | foo[0] ^= foo[1]; | |_____________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually - --> $DIR/swap.rs:121:5 + --> $DIR/swap.rs:123:5 | LL | / let temp = foo[0][1]; LL | | foo[0][1] = bar[1][0]; @@ -68,7 +68,7 @@ LL | | bar[1][0] = temp; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:135:7 + --> $DIR/swap.rs:137:7 | LL | ; let t = a; | _______^ @@ -79,7 +79,7 @@ LL | | b = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> $DIR/swap.rs:144:7 + --> $DIR/swap.rs:146:7 | LL | ; let t = c.0; | _______^ @@ -90,7 +90,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `b` and `a` manually - --> $DIR/swap.rs:170:5 + --> $DIR/swap.rs:172:5 | LL | / let t = b; LL | | b = a; @@ -100,7 +100,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:132:5 + --> $DIR/swap.rs:134:5 | LL | / a = b; LL | | b = a; @@ -110,7 +110,7 @@ LL | | b = a; = note: `-D clippy::almost-swapped` implied by `-D warnings` error: this looks like you are trying to swap `c.0` and `a` - --> $DIR/swap.rs:141:5 + --> $DIR/swap.rs:143:5 | LL | / c.0 = a; LL | | a = c.0; @@ -119,7 +119,7 @@ LL | | a = c.0; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:148:5 + --> $DIR/swap.rs:150:5 | LL | / let a = b; LL | | let b = a; @@ -128,7 +128,7 @@ LL | | let b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `d` and `c` - --> $DIR/swap.rs:153:5 + --> $DIR/swap.rs:155:5 | LL | / d = c; LL | | c = d; @@ -137,7 +137,7 @@ LL | | c = d; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:157:5 + --> $DIR/swap.rs:159:5 | LL | / let a = b; LL | | b = a; @@ -146,7 +146,7 @@ LL | | b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `s.0.x` and `s.0.y` manually - --> $DIR/swap.rs:205:5 + --> $DIR/swap.rs:207:5 | LL | / let t = s.0.x; LL | | s.0.x = s.0.y; diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed index 09fb66ca37e..174c858a47d 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed @@ -1,17 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, unused)] -#[macro_use] -extern crate macro_rules; - -macro_rules! gen_binding { - () => { - let _y = &42; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { // Closures should not warn let y = |ref x| println!("{:?}", x); @@ -38,13 +33,8 @@ fn main() { for ref _x in 0..10 {} // lint in macro - #[allow(unused)] - { - gen_binding!(); - } + inline!(let _y = &42;); // do not lint in external macro - { - ref_arg_binding!(); - } + external!(let ref _y = 42;); } diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs index 9d1f2f81098..4b81a06112f 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs @@ -1,17 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, unused)] -#[macro_use] -extern crate macro_rules; - -macro_rules! gen_binding { - () => { - let ref _y = 42; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { // Closures should not warn let y = |ref x| println!("{:?}", x); @@ -38,13 +33,8 @@ fn main() { for ref _x in 0..10 {} // lint in macro - #[allow(unused)] - { - gen_binding!(); - } + inline!(let ref _y = 42;); // do not lint in external macro - { - ref_arg_binding!(); - } + external!(let ref _y = 42;); } diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr index 9c853020ab0..407c2d9fcd3 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr @@ -1,5 +1,5 @@ error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:20:9 + --> $DIR/toplevel_ref_arg.rs:15:9 | LL | let ref _x = 1; | ----^^^^^^----- help: try: `let _x = &1;` @@ -7,39 +7,36 @@ LL | let ref _x = 1; = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:22:9 + --> $DIR/toplevel_ref_arg.rs:17:9 | LL | let ref _y: (&_, u8) = (&1, 2); | ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:24:9 + --> $DIR/toplevel_ref_arg.rs:19:9 | LL | let ref _z = 1 + 2; | ----^^^^^^--------- help: try: `let _z = &(1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:26:9 + --> $DIR/toplevel_ref_arg.rs:21:9 | LL | let ref mut _z = 1 + 2; | ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:31:9 + --> $DIR/toplevel_ref_arg.rs:26:9 | LL | let ref _x = vec![1, 2, 3]; | ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:11:13 + --> $DIR/toplevel_ref_arg.rs:36:17 | -LL | let ref _y = 42; - | ----^^^^^^------ help: try: `let _y = &42;` -... -LL | gen_binding!(); - | -------------- in this macro invocation +LL | inline!(let ref _y = 42;); + | ----^^^^^^------ help: try: `let _y = &42;` | - = note: this error originates in the macro `gen_binding` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs index 1a493fbce0e..2047593e7e4 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -1,33 +1,27 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(unused)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn the_answer(ref mut x: u8) { *x = 42; } -macro_rules! gen_function { - () => { - fn fun_example(ref _x: usize) {} - }; -} - +#[inline_macros] fn main() { let mut x = 0; the_answer(x); // lint in macro - #[allow(unused)] - { - gen_function!(); + inline! { + fn fun_example(ref _x: usize) {} } // do not lint in external macro - { - ref_arg_function!(); + external! { + fn fun_example2(ref _x: usize) {} } } diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr index e97011c7fd5..7307bd599d9 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr @@ -7,15 +7,12 @@ LL | fn the_answer(ref mut x: u8) { = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` directly on a function argument is ignored. Consider using a reference type instead - --> $DIR/toplevel_ref_arg_non_rustfix.rs:15:24 + --> $DIR/toplevel_ref_arg_non_rustfix.rs:20:24 | LL | fn fun_example(ref _x: usize) {} | ^^^^^^ -... -LL | gen_function!(); - | --------------- in this macro invocation | - = note: this error originates in the macro `gen_function` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed index 264194419c7..dc497b1690f 100644 --- a/src/tools/clippy/tests/ui/try_err.fixed +++ b/src/tools/clippy/tests/ui/try_err.fixed @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::io; use std::task::Poll; @@ -79,36 +79,22 @@ fn nested_error() -> Result<i32, i32> { Ok(1) } -// Bad suggestion when in macro (see #6242) -macro_rules! try_validation { - ($e: expr) => {{ - match $e { +#[inline_macros] +fn calling_macro() -> Result<i32, i32> { + // macro + inline!( + match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => return Err(1), } - }}; -} - -macro_rules! ret_one { - () => { - 1 - }; -} - -macro_rules! try_validation_in_macro { - ($e: expr) => {{ - match $e { + ); + // `Err` arg is another macro + inline!( + match $(Ok::<_, i32>(5)) { Ok(_) => 0, - Err(_) => return Err(ret_one!()), + Err(_) => return Err(inline!(1)), } - }}; -} - -fn calling_macro() -> Result<i32, i32> { - // macro - try_validation!(Ok::<_, i32>(5)); - // `Err` arg is another macro - try_validation_in_macro!(Ok::<_, i32>(5)); + ); Ok(5) } @@ -121,24 +107,19 @@ fn main() { calling_macro().unwrap(); // We don't want to lint in external macros - try_err!(); -} - -macro_rules! bar { - () => { - String::from("aasdfasdfasdfa") - }; -} - -macro_rules! foo { - () => { - bar!() - }; + external! { + pub fn try_err_fn() -> Result<i32, i32> { + let err: i32 = 1; + // To avoid warnings during rustfix + if true { Err(err)? } else { Ok(2) } + } + } } +#[inline_macros] pub fn macro_inside(fail: bool) -> Result<i32, String> { if fail { - return Err(foo!()); + return Err(inline!(inline!(String::from("aasdfasdfasdfa")))); } Ok(0) } diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs index bc6979bf457..86aeb75cd96 100644 --- a/src/tools/clippy/tests/ui/try_err.rs +++ b/src/tools/clippy/tests/ui/try_err.rs @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::io; use std::task::Poll; @@ -79,36 +79,22 @@ fn nested_error() -> Result<i32, i32> { Ok(1) } -// Bad suggestion when in macro (see #6242) -macro_rules! try_validation { - ($e: expr) => {{ - match $e { +#[inline_macros] +fn calling_macro() -> Result<i32, i32> { + // macro + inline!( + match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => Err(1)?, } - }}; -} - -macro_rules! ret_one { - () => { - 1 - }; -} - -macro_rules! try_validation_in_macro { - ($e: expr) => {{ - match $e { + ); + // `Err` arg is another macro + inline!( + match $(Ok::<_, i32>(5)) { Ok(_) => 0, - Err(_) => Err(ret_one!())?, + Err(_) => Err(inline!(1))?, } - }}; -} - -fn calling_macro() -> Result<i32, i32> { - // macro - try_validation!(Ok::<_, i32>(5)); - // `Err` arg is another macro - try_validation_in_macro!(Ok::<_, i32>(5)); + ); Ok(5) } @@ -121,24 +107,19 @@ fn main() { calling_macro().unwrap(); // We don't want to lint in external macros - try_err!(); -} - -macro_rules! bar { - () => { - String::from("aasdfasdfasdfa") - }; -} - -macro_rules! foo { - () => { - bar!() - }; + external! { + pub fn try_err_fn() -> Result<i32, i32> { + let err: i32 = 1; + // To avoid warnings during rustfix + if true { Err(err)? } else { Ok(2) } + } + } } +#[inline_macros] pub fn macro_inside(fail: bool) -> Result<i32, String> { if fail { - Err(foo!())?; + Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; } Ok(0) } diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr index 0cb1328fbfc..4ad0e2e56a4 100644 --- a/src/tools/clippy/tests/ui/try_err.stderr +++ b/src/tools/clippy/tests/ui/try_err.stderr @@ -29,53 +29,47 @@ LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:87:23 + --> $DIR/try_err.rs:88:23 | LL | Err(_) => Err(1)?, | ^^^^^^^ help: try this: `return Err(1)` -... -LL | try_validation!(Ok::<_, i32>(5)); - | -------------------------------- in this macro invocation | - = note: this error originates in the macro `try_validation` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:102:23 + --> $DIR/try_err.rs:95:23 | -LL | Err(_) => Err(ret_one!())?, - | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` -... -LL | try_validation_in_macro!(Ok::<_, i32>(5)); - | ----------------------------------------- in this macro invocation +LL | Err(_) => Err(inline!(1))?, + | ^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(1))` | - = note: this error originates in the macro `try_validation_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:141:9 + --> $DIR/try_err.rs:122:9 | -LL | Err(foo!())?; - | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` +LL | Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:148:9 + --> $DIR/try_err.rs:129:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:150:9 + --> $DIR/try_err.rs:131:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:158:9 + --> $DIR/try_err.rs:139:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:167:16 + --> $DIR/try_err.rs:148:16 | LL | return Err(42)?; | ^^^^^^^^ help: try this: `Err(42)` diff --git a/src/tools/clippy/tests/ui/uninit.rs b/src/tools/clippy/tests/ui/uninit.rs index 21131731708..412b36b4ee8 100644 --- a/src/tools/clippy/tests/ui/uninit.rs +++ b/src/tools/clippy/tests/ui/uninit.rs @@ -3,13 +3,15 @@ use std::mem::{self, MaybeUninit}; +union MyOwnMaybeUninit { + value: u8, + uninit: (), +} + fn main() { let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; - // edge case: For now we lint on empty arrays - let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; - - // edge case: For now we accept unit tuples + // This is OK, because ZSTs do not contain data. let _: () = unsafe { MaybeUninit::uninit().assume_init() }; // This is OK, because `MaybeUninit` allows uninitialized data. @@ -21,6 +23,19 @@ fn main() { // This is OK, because all constitutent types are uninit-compatible. let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() }; + // This is OK, because our own MaybeUninit is just as fine as the one from core. + let _: MyOwnMaybeUninit = unsafe { MaybeUninit::uninit().assume_init() }; + + // This is OK, because empty arrays don't contain data. + let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; + // Was a false negative. let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; + + polymorphic::<()>(); + + fn polymorphic<T>() { + // We are conservative around polymorphic types. + let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; + } } diff --git a/src/tools/clippy/tests/ui/uninit.stderr b/src/tools/clippy/tests/ui/uninit.stderr index 15ef2349489..9e01b9a4aa8 100644 --- a/src/tools/clippy/tests/ui/uninit.stderr +++ b/src/tools/clippy/tests/ui/uninit.stderr @@ -1,5 +1,5 @@ error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:7:29 + --> $DIR/uninit.rs:12:29 | LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,15 +7,15 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; = note: `#[deny(clippy::uninit_assumed_init)]` on by default error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:10:31 + --> $DIR/uninit.rs:33:29 | -LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:25:29 + --> $DIR/uninit.rs:39:29 | -LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; +LL | let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/uninit_vec.rs b/src/tools/clippy/tests/ui/uninit_vec.rs index 194e4fc157e..59ec64a7ab1 100644 --- a/src/tools/clippy/tests/ui/uninit_vec.rs +++ b/src/tools/clippy/tests/ui/uninit_vec.rs @@ -7,6 +7,11 @@ struct MyVec { vec: Vec<u8>, } +union MyOwnMaybeUninit { + value: u8, + uninit: (), +} + fn main() { // with_capacity() -> set_len() should be detected let mut vec: Vec<u8> = Vec::with_capacity(1000); @@ -97,4 +102,26 @@ fn main() { unsafe { vec.set_len(0); } + + // ZSTs should not be detected + let mut vec: Vec<()> = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + + // unions should not be detected + let mut vec: Vec<MyOwnMaybeUninit> = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + + polymorphic::<()>(); + + fn polymorphic<T>() { + // We are conservative around polymorphic types. + let mut vec: Vec<T> = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + } } diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr index 77fc689f076..9cdf0c95ad9 100644 --- a/src/tools/clippy/tests/ui/uninit_vec.stderr +++ b/src/tools/clippy/tests/ui/uninit_vec.stderr @@ -1,5 +1,5 @@ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:12:5 + --> $DIR/uninit_vec.rs:17:5 | LL | let mut vec: Vec<u8> = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | vec.set_len(200); = note: `-D clippy::uninit-vec` implied by `-D warnings` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:18:5 + --> $DIR/uninit_vec.rs:23:5 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:24:5 + --> $DIR/uninit_vec.rs:29:5 | LL | let mut vec: Vec<u8> = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:30:5 + --> $DIR/uninit_vec.rs:35:5 | LL | let mut vec: Vec<u8> = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:35:5 + --> $DIR/uninit_vec.rs:40:5 | LL | let mut vec: Vec<u8> = Vec::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:49:5 + --> $DIR/uninit_vec.rs:54:5 | LL | let mut vec: Vec<u8> = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:58:5 + --> $DIR/uninit_vec.rs:63:5 | LL | my_vec.vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:63:5 + --> $DIR/uninit_vec.rs:68:5 | LL | my_vec.vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:42:9 + --> $DIR/uninit_vec.rs:47:9 | LL | let mut vec: Vec<u8> = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:45:9 + --> $DIR/uninit_vec.rs:50:9 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -101,5 +101,16 @@ LL | vec.set_len(200); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 10 previous errors +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:122:9 + | +LL | let mut vec: Vec<T> = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(10); + | ^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.fixed b/src/tools/clippy/tests/ui/uninlined_format_args.fixed index cbd5cc5fcee..1475d781c67 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.fixed +++ b/src/tools/clippy/tests/ui/uninlined_format_args.fixed @@ -1,11 +1,11 @@ -// aux-build:proc_macro_with_span.rs +// aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; macro_rules! no_param_str { () => { diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.rs b/src/tools/clippy/tests/ui/uninlined_format_args.rs index cf0ea5be481..835afac393f 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.rs +++ b/src/tools/clippy/tests/ui/uninlined_format_args.rs @@ -1,11 +1,11 @@ -// aux-build:proc_macro_with_span.rs +// aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; macro_rules! no_param_str { () => { diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index 07e70873a81..674ae4f1df9 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow( @@ -13,9 +13,9 @@ clippy::unused_unit )] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::fmt::Debug; fn foo<T: Debug>(t: T) { diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed index 22e9bd8bdc5..3b93800f8b7 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Deep(Option<usize>); diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs index 8726d84a23f..2851c0c5190 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Deep(Option<usize>); diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed index 65d9c910b82..b046694f8c6 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed @@ -1,6 +1,12 @@ // run-rustfix -#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] +#![allow( + clippy::deref_addrof, + dead_code, + unused, + clippy::no_effect, + clippy::unnecessary_struct_initialization +)] #![warn(clippy::unnecessary_operation)] struct Tuple(i32); diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs index 4e2acd59f04..9ed9679e938 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.rs +++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs @@ -1,6 +1,12 @@ // run-rustfix -#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] +#![allow( + clippy::deref_addrof, + dead_code, + unused, + clippy::no_effect, + clippy::unnecessary_struct_initialization +)] #![warn(clippy::unnecessary_operation)] struct Tuple(i32); diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr index 44cf2e01ff7..a1d0d93998a 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr @@ -1,5 +1,5 @@ error: unnecessary operation - --> $DIR/unnecessary_operation.rs:50:5 + --> $DIR/unnecessary_operation.rs:56:5 | LL | Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` @@ -7,103 +7,103 @@ LL | Tuple(get_number()); = note: `-D clippy::unnecessary-operation` implied by `-D warnings` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:51:5 + --> $DIR/unnecessary_operation.rs:57:5 | LL | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:52:5 + --> $DIR/unnecessary_operation.rs:58:5 | LL | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:53:5 + --> $DIR/unnecessary_operation.rs:59:5 | LL | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:54:5 + --> $DIR/unnecessary_operation.rs:60:5 | LL | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:55:5 + --> $DIR/unnecessary_operation.rs:61:5 | LL | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:56:5 + --> $DIR/unnecessary_operation.rs:62:5 | LL | *&get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:57:5 + --> $DIR/unnecessary_operation.rs:63:5 | LL | &get_number(); | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:58:5 + --> $DIR/unnecessary_operation.rs:64:5 | LL | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:59:5 + --> $DIR/unnecessary_operation.rs:65:5 | LL | get_number()..; | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:60:5 + --> $DIR/unnecessary_operation.rs:66:5 | LL | ..get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:61:5 + --> $DIR/unnecessary_operation.rs:67:5 | LL | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:62:5 + --> $DIR/unnecessary_operation.rs:68:5 | LL | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:63:5 + --> $DIR/unnecessary_operation.rs:69:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:64:5 + --> $DIR/unnecessary_operation.rs:70:5 | LL | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:65:5 + --> $DIR/unnecessary_operation.rs:71:5 | LL | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:66:5 + --> $DIR/unnecessary_operation.rs:72:5 | LL | [42; 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:67:5 + --> $DIR/unnecessary_operation.rs:73:5 | LL | / { LL | | get_number() @@ -111,7 +111,7 @@ LL | | }; | |______^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:70:5 + --> $DIR/unnecessary_operation.rs:76:5 | LL | / FooString { LL | | s: String::from("blah"), diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed new file mode 100644 index 00000000000..b47129e4a36 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed @@ -0,0 +1,73 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::unnecessary_struct_initialization)] + +struct S { + f: String, +} + +#[derive(Clone, Copy)] +struct T { + f: u32, +} + +struct U { + f: u32, +} + +impl Clone for U { + fn clone(&self) -> Self { + // Do not lint: `Self` does not implement `Copy` + Self { ..*self } + } +} + +#[derive(Copy)] +struct V { + f: u32, +} + +impl Clone for V { + fn clone(&self) -> Self { + // Lint: `Self` implements `Copy` + *self + } +} + +fn main() { + // Should lint: `a` would be consumed anyway + let a = S { f: String::from("foo") }; + let mut b = a; + + // Should lint: `b` would be consumed, and is mutable + let c = &mut b; + + // Should not lint as `d` is not mutable + let d = S { f: String::from("foo") }; + let e = &mut S { ..d }; + + // Should lint as `f` would be consumed anyway + let f = S { f: String::from("foo") }; + let g = &f; + + // Should lint: the result of an expression is mutable + let h = &mut *Box::new(S { f: String::from("foo") }); + + // Should not lint: `m` would be both alive and borrowed + let m = T { f: 17 }; + let n = &T { ..m }; + + // Should not lint: `m` should not be modified + let o = &mut T { ..m }; + o.f = 32; + assert_eq!(m.f, 17); + + // Should not lint: `m` should not be modified + let o = &mut T { ..m } as *mut T; + unsafe { &mut *o }.f = 32; + assert_eq!(m.f, 17); + + // Should lint: the result of an expression is mutable and temporary + let p = &mut *Box::new(T { f: 5 }); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs new file mode 100644 index 00000000000..63b11c626e5 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs @@ -0,0 +1,77 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::unnecessary_struct_initialization)] + +struct S { + f: String, +} + +#[derive(Clone, Copy)] +struct T { + f: u32, +} + +struct U { + f: u32, +} + +impl Clone for U { + fn clone(&self) -> Self { + // Do not lint: `Self` does not implement `Copy` + Self { ..*self } + } +} + +#[derive(Copy)] +struct V { + f: u32, +} + +impl Clone for V { + fn clone(&self) -> Self { + // Lint: `Self` implements `Copy` + Self { ..*self } + } +} + +fn main() { + // Should lint: `a` would be consumed anyway + let a = S { f: String::from("foo") }; + let mut b = S { ..a }; + + // Should lint: `b` would be consumed, and is mutable + let c = &mut S { ..b }; + + // Should not lint as `d` is not mutable + let d = S { f: String::from("foo") }; + let e = &mut S { ..d }; + + // Should lint as `f` would be consumed anyway + let f = S { f: String::from("foo") }; + let g = &S { ..f }; + + // Should lint: the result of an expression is mutable + let h = &mut S { + ..*Box::new(S { f: String::from("foo") }) + }; + + // Should not lint: `m` would be both alive and borrowed + let m = T { f: 17 }; + let n = &T { ..m }; + + // Should not lint: `m` should not be modified + let o = &mut T { ..m }; + o.f = 32; + assert_eq!(m.f, 17); + + // Should not lint: `m` should not be modified + let o = &mut T { ..m } as *mut T; + unsafe { &mut *o }.f = 32; + assert_eq!(m.f, 17); + + // Should lint: the result of an expression is mutable and temporary + let p = &mut T { + ..*Box::new(T { f: 5 }) + }; +} diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr new file mode 100644 index 00000000000..ca497057702 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr @@ -0,0 +1,46 @@ +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:34:9 + | +LL | Self { ..*self } + | ^^^^^^^^^^^^^^^^ help: replace with: `*self` + | + = note: `-D clippy::unnecessary-struct-initialization` implied by `-D warnings` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:41:17 + | +LL | let mut b = S { ..a }; + | ^^^^^^^^^ help: replace with: `a` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:44:18 + | +LL | let c = &mut S { ..b }; + | ^^^^^^^^^ help: replace with: `b` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:52:14 + | +LL | let g = &S { ..f }; + | ^^^^^^^^^ help: replace with: `f` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:55:18 + | +LL | let h = &mut S { + | __________________^ +LL | | ..*Box::new(S { f: String::from("foo") }) +LL | | }; + | |_____^ help: replace with: `*Box::new(S { f: String::from("foo") })` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:74:18 + | +LL | let p = &mut T { + | __________________^ +LL | | ..*Box::new(T { f: 5 }) +LL | | }; + | |_____^ help: replace with: `*Box::new(T { f: 5 })` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs index c160e31afd3..431093ab369 100644 --- a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs +++ b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs @@ -1,10 +1,10 @@ -// aux-build:doc_unsafe_macros.rs +// aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] #![warn(clippy::unnecessary_safety_doc)] -#[macro_use] -extern crate doc_unsafe_macros; +extern crate proc_macros; +use proc_macros::external; /// This is has no safety section, and does not need one either pub fn destroy_the_planet() { @@ -129,7 +129,11 @@ macro_rules! very_safe { very_safe!(); // we don't lint code from external macros -undocd_safe!(); +external!( + pub fn vey_oy() { + unimplemented!(); + } +); fn main() {} diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr index 72898c93fa1..b0f20fdac5f 100644 --- a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr @@ -42,7 +42,7 @@ LL | very_safe!(); = note: this error originates in the macro `very_safe` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for safe trait have unnecessary `# Safety` section - --> $DIR/unnecessary_unsafety_doc.rs:147:1 + --> $DIR/unnecessary_unsafety_doc.rs:151:1 | LL | pub trait DocumentedSafeTraitWithImplementationHeader { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 6f50ef932e1..3f8f6a7b98c 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -17,6 +17,7 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB [assign.owners] "/.github" = ["@flip1995"] +"/util/gh-pages" = ["@xFrednet"] "*" = [ "@flip1995", "@Manishearth", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 0db043a4fca..85fd6523c82 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -26,4 +26,10 @@ libc = "0.2" [target.'cfg(windows)'.dependencies] miow = "0.5" -winapi = { version = "0.3", features = ["winerror"] } + +[target.'cfg(windows)'.dependencies.windows] +version = "0.46.0" +features = [ + "Win32_Foundation", + "Win32_System_Diagnostics_Debug", +] diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 7fe2e6257d9..7691f5c32b2 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -9,7 +9,7 @@ use std::str::FromStr; use crate::util::{add_dylib_path, PathBufExt}; use lazycell::LazyCell; -use test::ColorConfig; +use test::{ColorConfig, OutputFormat}; #[derive(Clone, Copy, PartialEq, Debug)] pub enum Mode { @@ -337,7 +337,7 @@ pub struct Config { pub verbose: bool, /// Print one character per test instead of one line - pub quiet: bool, + pub format: OutputFormat, /// Whether to use colors in test. pub color: ColorConfig, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index d9b39927ca4..5bc9d9afcb9 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -964,6 +964,19 @@ pub fn make_test_description<R: Read>( .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) .exists(); + fn is_on_path(file: &'static str) -> impl Fn() -> bool { + move || env::split_paths(&env::var_os("PATH").unwrap()).any(|dir| dir.join(file).is_file()) + } + + // On Windows, dlltool.exe is used for all architectures. + #[cfg(windows)] + let (has_i686_dlltool, has_x86_64_dlltool) = + (is_on_path("dlltool.exe"), is_on_path("dlltool.exe")); + // For non-Windows, there are architecture specific dlltool binaries. + #[cfg(not(windows))] + let (has_i686_dlltool, has_x86_64_dlltool) = + (is_on_path("i686-w64-mingw32-dlltool"), is_on_path("x86_64-w64-mingw32-dlltool")); + iter_header(path, src, &mut |revision, ln| { if revision.is_some() && revision != cfg { return; @@ -1031,6 +1044,8 @@ pub fn make_test_description<R: Read>( reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln)); reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln)); reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld")); + reason!(config.parse_name_directive(ln, "needs-i686-dlltool") && !has_i686_dlltool()); + reason!(config.parse_name_directive(ln, "needs-x86_64-dlltool") && !has_x86_64_dlltool()); should_fail |= config.parse_name_directive(ln, "should-fail"); }); @@ -1047,6 +1062,16 @@ pub fn make_test_description<R: Read>( name, ignore, ignore_message, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic, compile_fail: false, no_run: false, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 1760c29ec66..cbaa599f793 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -114,6 +114,7 @@ pub fn parse_config(args: Vec<String>) -> Config { ) .optflag("", "quiet", "print one character per test instead of one line") .optopt("", "color", "coloring: auto, always, never", "WHEN") + .optflag("", "json", "emit json output instead of plaintext output") .optopt("", "logfile", "file to log test execution to", "FILE") .optopt("", "target", "the target to build for", "TARGET") .optopt("", "host", "the host to build for", "HOST") @@ -281,7 +282,12 @@ pub fn parse_config(args: Vec<String>) -> Config { && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), lldb_python_dir: matches.opt_str("lldb-python-dir"), verbose: matches.opt_present("verbose"), - quiet: matches.opt_present("quiet"), + format: match (matches.opt_present("quiet"), matches.opt_present("json")) { + (true, true) => panic!("--quiet and --json are incompatible"), + (true, false) => test::OutputFormat::Terse, + (false, true) => test::OutputFormat::Json, + (false, false) => test::OutputFormat::Pretty, + }, only_modified: matches.opt_present("only-modified"), color, remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), @@ -339,7 +345,7 @@ pub fn log_config(config: &Config) { logv(c, format!("ar: {}", config.ar)); logv(c, format!("linker: {:?}", config.linker)); logv(c, format!("verbose: {}", config.verbose)); - logv(c, format!("quiet: {}", config.quiet)); + logv(c, format!("format: {:?}", config.format)); logv(c, "\n".to_string()); } @@ -416,7 +422,7 @@ pub fn run_tests(config: Config) { // easy to miss which tests failed, and as such fail to reproduce // the failure locally. - eprintln!( + println!( "Some tests failed in compiletest suite={}{} mode={} host={} target={}", config.suite, config.compare_mode.map(|c| format!(" compare_mode={:?}", c)).unwrap_or_default(), @@ -501,7 +507,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { filters: config.filters.clone(), filter_exact: config.filter_exact, run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: if config.quiet { test::OutputFormat::Terse } else { test::OutputFormat::Pretty }, + format: config.format, logfile: config.logfile.clone(), run_tests: true, bench_benchmarks: true, diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index a5dc6859732..725f7a1515c 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -232,7 +232,7 @@ mod imp { use miow::iocp::{CompletionPort, CompletionStatus}; use miow::pipe::NamedPipe; use miow::Overlapped; - use winapi::shared::winerror::ERROR_BROKEN_PIPE; + use windows::Win32::Foundation::ERROR_BROKEN_PIPE; struct Pipe<'a> { dst: &'a mut Vec<u8>, @@ -295,7 +295,7 @@ mod imp { match self.pipe.read_overlapped(dst, self.overlapped.raw()) { Ok(_) => Ok(()), Err(e) => { - if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) { + if e.raw_os_error() == Some(ERROR_BROKEN_PIPE.0 as i32) { self.done = true; Ok(()) } else { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a127875b55d..a4003072310 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -49,8 +49,10 @@ const FAKE_SRC_BASE: &str = "fake-test-src-base"; #[cfg(windows)] fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R { use std::sync::Mutex; - use winapi::um::errhandlingapi::SetErrorMode; - use winapi::um::winbase::SEM_NOGPFAULTERRORBOX; + + use windows::Win32::System::Diagnostics::Debug::{ + SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE, + }; static LOCK: Mutex<()> = Mutex::new(()); @@ -62,6 +64,7 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R { // termination by design. This mode is inherited by all child processes. unsafe { let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags + let old_mode = THREAD_ERROR_MODE(old_mode); SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX); let r = f(); SetErrorMode(old_mode); @@ -278,13 +281,15 @@ impl<'test> TestCx<'test> { Incremental => { let revision = self.revision.expect("incremental tests require a list of revisions"); - if revision.starts_with("rpass") || revision.starts_with("rfail") { + if revision.starts_with("cpass") + || revision.starts_with("rpass") + || revision.starts_with("rfail") + { true } else if revision.starts_with("cfail") { - // FIXME: would be nice if incremental revs could start with "cpass" pm.is_some() } else { - panic!("revision name must begin with rpass, rfail, or cfail"); + panic!("revision name must begin with cpass, rpass, rfail, or cfail"); } } mode => panic!("unimplemented for mode {:?}", mode), @@ -384,6 +389,20 @@ impl<'test> TestCx<'test> { } } + fn run_cpass_test(&self) { + let emit_metadata = self.should_emit_metadata(self.pass_mode()); + let proc_res = self.compile_test(WillExecute::No, emit_metadata); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + // FIXME(#41968): Move this check to tidy? + if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { + self.fatal("compile-pass tests with expected warnings should be moved to ui/"); + } + } + fn run_rpass_test(&self) { let emit_metadata = self.should_emit_metadata(self.pass_mode()); let should_run = self.run_if_enabled(); @@ -393,17 +412,15 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("compilation failed!", &proc_res); } + // FIXME(#41968): Move this check to tidy? + if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { + self.fatal("run-pass tests with expected warnings should be moved to ui/"); + } + if let WillExecute::Disabled = should_run { return; } - // FIXME(#41968): Move this check to tidy? - let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - assert!( - expected_errors.is_empty(), - "run-pass tests with expected warnings should be moved to ui/" - ); - let proc_res = self.exec_compiled_test(); if !proc_res.status.success() { self.fatal_proc_rec("test run failed!", &proc_res); @@ -2913,10 +2930,11 @@ impl<'test> TestCx<'test> { fn run_incremental_test(&self) { // Basic plan for a test incremental/foo/bar.rs: // - load list of revisions rpass1, cfail2, rpass3 - // - each should begin with `rpass`, `cfail`, or `rfail` - // - if `rpass`, expect compile and execution to succeed + // - each should begin with `cpass`, `rpass`, `cfail`, or `rfail` + // - if `cpass`, expect compilation to succeed, don't execute + // - if `rpass`, expect compilation and execution to succeed // - if `cfail`, expect compilation to fail - // - if `rfail`, expect execution to fail + // - if `rfail`, expect compilation to succeed and execution to fail // - create a directory build/foo/bar.incremental // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1 // - because name of revision starts with "rpass", expect success @@ -2940,7 +2958,12 @@ impl<'test> TestCx<'test> { print!("revision={:?} props={:#?}", revision, self.props); } - if revision.starts_with("rpass") { + if revision.starts_with("cpass") { + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); + } + self.run_cpass_test(); + } else if revision.starts_with("rpass") { if self.props.should_ice { self.fatal("can only use should-ice in cfail tests"); } @@ -2953,7 +2976,7 @@ impl<'test> TestCx<'test> { } else if revision.starts_with("cfail") { self.run_cfail_test(); } else { - self.fatal("revision name must begin with rpass, rfail, or cfail"); + self.fatal("revision name must begin with cpass, rpass, rfail, or cfail"); } } diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 3842a649c6f..034c6aa0708 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -45,6 +45,36 @@ impl Lint { fn check_style(&self) -> Result<(), Box<dyn Error>> { for &expected in &["### Example", "### Explanation", "{{produces}}"] { if expected == "{{produces}}" && self.is_ignored() { + if self.doc_contains("{{produces}}") { + return Err(format!( + "the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\ + \n\ + The documentation generator cannot generate the example output when the \ + example is ignored.\n\ + Manually include the sample output below the example. For example:\n\ + \n\ + /// ```rust,ignore (needs command line option)\n\ + /// #[cfg(widnows)]\n\ + /// fn foo() {{}}\n\ + /// ```\n\ + ///\n\ + /// This will produce:\n\ + /// \n\ + /// ```text\n\ + /// warning: unknown condition name used\n\ + /// --> lint_example.rs:1:7\n\ + /// |\n\ + /// 1 | #[cfg(widnows)]\n\ + /// | ^^^^^^^\n\ + /// |\n\ + /// = note: `#[warn(unexpected_cfgs)]` on by default\n\ + /// ```\n\ + \n\ + Replacing the output with the text of the example you \ + compiled manually yourself.\n\ + " + ).into()); + } continue; } if !self.doc_contains(expected) { @@ -317,10 +347,10 @@ impl<'a> LintExtractor<'a> { .., &format!( "This will produce:\n\ - \n\ - ```text\n\ - {}\ - ```", + \n\ + ```text\n\ + {}\ + ```", output ), ); @@ -392,37 +422,36 @@ impl<'a> LintExtractor<'a> { .filter(|line| line.starts_with('{')) .map(serde_json::from_str) .collect::<Result<Vec<serde_json::Value>, _>>()?; - match msgs + // First try to find the messages with the `code` field set to our lint. + let matches: Vec<_> = msgs .iter() - .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) - { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) - } - None => { - match msgs.iter().find( - |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), - ) { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) - } - None => { - let rendered: Vec<&str> = - msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); - let non_json: Vec<&str> = - stderr.lines().filter(|line| !line.starts_with('{')).collect(); - Err(format!( - "did not find lint `{}` in output of example, got:\n{}\n{}", - name, - non_json.join("\n"), - rendered.join("\n") - ) - .into()) - } - } + .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) + .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string()) + .collect(); + if matches.is_empty() { + // Some lints override their code to something else (E0566). + // Try to find something that looks like it could be our lint. + let matches: Vec<_> = msgs.iter().filter(|msg| + matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name))) + .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string()) + .collect(); + if matches.is_empty() { + let rendered: Vec<&str> = + msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); + Err(format!( + "did not find lint `{}` in output of example, got:\n{}\n{}", + name, + non_json.join("\n"), + rendered.join("\n") + ) + .into()) + } else { + Ok(matches.join("\n")) } + } else { + Ok(matches.join("\n")) } } diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 138a69974e1..b71f48e4644 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -54,8 +54,8 @@ jobs: # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo + key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-reset20230315 - name: Install rustup-toolchain-install-master if: ${{ steps.cache.outputs.cache-hit != 'true' }} @@ -106,8 +106,8 @@ jobs: # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo + key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-reset20230315 - name: Install rustup-toolchain-install-master if: ${{ steps.cache.outputs.cache-hit != 'true' }} diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 476075e9c91..bcdb623b090 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -129,18 +129,15 @@ development version of Miri using ./miri install ``` -and then you can use it as if it was installed by `rustup`. Make sure you use -the same toolchain when calling `cargo miri` that you used when installing Miri! -Usually this means you have to write `cargo +miri miri ...` to select the `miri` -toolchain that was installed by `./miri toolchain`. +and then you can use it as if it was installed by `rustup` as a component of the +`miri` toolchain. Note that the `miri` and `cargo-miri` executables are placed +in the `miri` toolchain's sysroot to prevent conflicts with other toolchains. +The Miri binaries in the `cargo` bin directory (usually `~/.cargo/bin`) are managed by rustup. There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. -Note that installing Miri like this will "take away" Miri management from `rustup`. -If you want to later go back to a rustup-installed Miri, run `rustup update`. - ### Using a modified standard library Miri re-builds the standard library into a custom sysroot, so it is fairly easy diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 1086d0481c8..b70f7e0e556 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -15,6 +15,8 @@ for example: or an invalid enum discriminant) * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types +* **Experimental**: Violations of the Tree Borrows aliasing rules, as an optional + alternative to [Stacked Borrows] * **Experimental**: Data races On top of that, Miri will also tell you about memory leaks: when there is memory @@ -225,6 +227,26 @@ degree documented below): reduced feature set. We might ship Miri with a nightly even when some features on these targets regress. +### Running tests in parallel + +Though it implements Rust threading, Miri itself is a single-threaded interpreter. +This means that when running `cargo miri test`, you will probably see a dramatic +increase in the amount of time it takes to run your whole test suite due to the +inherent interpreter slowdown and a loss of parallelism. + +You can get your test suite's parallelism back by running `cargo miri nextest run -jN` +(note that you will need [`cargo-nextest`](https://nexte.st) installed). +This works because `cargo-nextest` collects a list of all tests then launches a +separate `cargo miri run` for each test. You will need to specify a `-j` or `--test-threads`; +by default `cargo miri nextest run` runs one test at a time. For more details, see the +[`cargo-nextest` Miri documentation](https://nexte.st/book/miri.html). + +Note: This one-test-per-process model means that `cargo miri test` is able to detect data +races where two tests race on a shared resource, but `cargo miri nextest run` will not detect +such races. + +Note: `cargo-nextest` does not support doctests, see https://github.com/nextest-rs/nextest/issues/16 + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler @@ -337,9 +359,11 @@ to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-disable-data-race-detector` disables checking for data races. Using this flag is **unsound**. This implies `-Zmiri-disable-weak-memory-emulation`. * `-Zmiri-disable-stacked-borrows` disables checking the experimental - [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also - means no aliasing violations will be detected. Using this flag is **unsound** - (but the affected soundness rules are experimental). + aliasing rules to track borrows ([Stacked Borrows] and Tree Borrows). + This can make Miri run faster, but it also means no aliasing violations will + be detected. Using this flag is **unsound** (but the affected soundness rules + are experimental). Later flags take precedence: borrow tracking can be reactivated + by `-Zmiri-tree-borrows`. * `-Zmiri-disable-validation` disables enforcing validity invariants, which are enforced by default. This is mostly useful to focus on other failures (such as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs @@ -401,6 +425,9 @@ to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-track-weak-memory-loads` shows a backtrace when weak memory emulation returns an outdated value from a load. This can help diagnose problems that disappear under `-Zmiri-disable-weak-memory-emulation`. +* `-Zmiri-tree-borrows` replaces [Stacked Borrows] with the Tree Borrows rules. + The soundness rules are already experimental without this flag, but even more + so with this flag. * `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k. `4` is default for most targets. This value should always be a power of 2 and nonzero. @@ -415,7 +442,7 @@ Some native rustc `-Z` flags are also very relevant for Miri: functions. This is needed so that Miri can execute such functions, so Miri sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri - enables this per default because it is needed for [Stacked Borrows]. + enables this per default because it is needed for [Stacked Borrows] and Tree Borrows. Moreover, Miri recognizes some environment variables: @@ -481,120 +508,8 @@ binaries, and as such worth documenting: ## Miri `extern` functions Miri provides some `extern` functions that programs can import to access -Miri-specific functionality: - -```rust -#[cfg(miri)] -extern "Rust" { - /// Miri-provided extern function to mark the block `ptr` points to as a "root" - /// for some static memory. This memory and everything reachable by it is not - /// considered leaking even if it still exists when the program terminates. - /// - /// `ptr` has to point to the beginning of an allocated block. - fn miri_static_root(ptr: *const u8); - - // Miri-provided extern function to get the amount of frames in the current backtrace. - // The `flags` argument must be `0`. - fn miri_backtrace_size(flags: u64) -> usize; - - /// Miri-provided extern function to obtain a backtrace of the current call stack. - /// This writes a slice of pointers into `buf` - each pointer is an opaque value - /// that is only useful when passed to `miri_resolve_frame`. - /// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space. - /// The `flags` argument must be `1`. - fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); - - /// Miri-provided extern function to resolve a frame pointer obtained - /// from `miri_get_backtrace`. The `flags` argument must be `1`, - /// and `MiriFrame` should be declared as follows: - /// - /// ```rust - /// #[repr(C)] - /// struct MiriFrame { - /// // The size of the name of the function being executed, encoded in UTF-8 - /// name_len: usize, - /// // The size of filename of the function being executed, encoded in UTF-8 - /// filename_len: usize, - /// // The line number currently being executed in `filename`, starting from '1'. - /// lineno: u32, - /// // The column number currently being executed in `filename`, starting from '1'. - /// colno: u32, - /// // The function pointer to the function currently being executed. - /// // This can be compared against function pointers obtained by - /// // casting a function (e.g. `my_fn as *mut ()`) - /// fn_ptr: *mut () - /// } - /// ``` - /// - /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above. - /// This function can be called on any thread (not just the one which obtained `frame`). - fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; - - /// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`. - /// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`. - /// The flags argument must be `0`. - fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); - - /// Miri-provided extern function to begin unwinding with the given payload. - /// - /// This is internal and unstable and should not be used; we give it here - /// just to be complete. - fn miri_start_panic(payload: *mut u8) -> !; - - /// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer - /// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort. - /// - /// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because - /// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation. - /// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so - /// inherits all of its instability. - fn miri_get_alloc_id(ptr: *const ()) -> u64; - - /// Miri-provided extern function to print (from the interpreter, not the program) the contents of all - /// borrow stacks in an allocation. The leftmost tag is the bottom of the stack. - /// The format of what this emits is unstable and may change at any time. In particular, users should be - /// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of - /// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC. - /// - /// This function is extremely unstable. At any time the format of its output may change, its signature may - /// change, or it may be removed entirely. - fn miri_print_borrow_stacks(alloc_id: u64); - - /// Miri-provided extern function to print (from the interpreter, not the - /// program) the contents of a section of program memory, as bytes. Bytes - /// written using this function will emerge from the interpreter's stdout. - fn miri_write_to_stdout(bytes: &[u8]); - - /// Miri-provided extern function to print (from the interpreter, not the - /// program) the contents of a section of program memory, as bytes. Bytes - /// written using this function will emerge from the interpreter's stderr. - fn miri_write_to_stderr(bytes: &[u8]); - - /// Miri-provided extern function to allocate memory from the interpreter. - /// - /// This is useful when no fundamental way of allocating memory is - /// available, e.g. when using `no_std` + `alloc`. - fn miri_alloc(size: usize, align: usize) -> *mut u8; - - /// Miri-provided extern function to deallocate memory. - fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); - - /// Convert a path from the host Miri runs on to the target Miri interprets. - /// Performs conversion of path separators as needed. - /// - /// Usually Miri performs this kind of conversion automatically. However, manual conversion - /// might be necessary when reading an environment variable that was set on the host - /// (such as TMPDIR) and using it as a target path. - /// - /// Only works with isolation disabled. - /// - /// `in` must point to a null-terminated string, and will be read as the input host path. - /// `out` must point to at least `out_size` many bytes, and the result will be stored there - /// with a null terminator. - /// Returns 0 if the `out` buffer was large enough, and the required size otherwise. - fn miri_host_to_target_path(path: *const std::ffi::c_char, out: *mut std::ffi::c_char, out_size: usize) -> usize; -} -``` +Miri-specific functionality. They are declared in +[/tests/utils/miri\_extern.rs](/tests/utils/miri_extern.rs). ## Contributing and getting help diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh index 60450d09815..ef52a37fe31 100755 --- a/src/tools/miri/ci.sh +++ b/src/tools/miri/ci.sh @@ -62,8 +62,8 @@ function run_tests { if [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then # These act up on Windows (`which miri` produces a filename that does not exist?!?), # so let's do this only on Linux. Also makes sure things work without these set. - export RUSTC=$(which rustc) - export MIRI=$(which miri) + export RUSTC=$(which rustc) # Produces a warning unless we also set MIRI + export MIRI=$(rustc +miri --print sysroot)/bin/miri fi mkdir -p .cargo echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml diff --git a/src/tools/miri/miri b/src/tools/miri/miri index 0c0bbbc7020..1073ff499ba 100755 --- a/src/tools/miri/miri +++ b/src/tools/miri/miri @@ -6,8 +6,8 @@ USAGE=$(cat <<"EOF" ./miri install <flags>: Installs the miri driver and cargo-miri. <flags> are passed to `cargo install`. Sets up the rpath such that the installed binary should work in any -working directory. However, the rustup toolchain when invoking `cargo miri` -needs to be the same one used for `./miri install`. +working directory. Note that the binaries are placed in the `miri` toolchain +sysroot, to prevent conflicts with other toolchains. ./miri build <flags>: Just build miri. <flags> are passed to `cargo build`. @@ -281,8 +281,9 @@ find_sysroot() { case "$COMMAND" in install) # "--locked" to respect the Cargo.lock file if it exists. - $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked "$@" - $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked "$@" + # Install binaries to the miri toolchain's sysroot so they do not interact with other toolchains. + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked --root "$SYSROOT" "$@" + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --root "$SYSROOT" "$@" ;; check) # Check, and let caller control flags. diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 53ec1ba0821..18c2561242a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -c4e0cd966062ca67daed20775f4e8a60c28e57df +511364e7874dba9649a264100407e4bffe7b5425 diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index a2caeb97297..0aea105ccc4 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -22,17 +22,18 @@ use log::debug; use rustc_data_structures::sync::Lrc; use rustc_driver::Compilation; -use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; +use rustc_hir::{self as hir, Node}; use rustc_interface::interface::Config; use rustc_middle::{ middle::exported_symbols::{ ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }, ty::{query::ExternProviders, TyCtxt}, + query::LocalCrate, }; use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace}; -use miri::{BacktraceStyle, ProvenanceMode, RetagFields}; +use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -107,8 +108,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { config.override_queries = Some(|_, local_providers, _| { // `exported_symbols` and `reachable_non_generics` provided by rustc always returns // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false. - local_providers.exported_symbols = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); + local_providers.exported_symbols = |tcx, LocalCrate| { let reachable_set = tcx.with_stable_hashing_context(|hcx| { tcx.reachable_set(()).to_sorted(&hcx, true) }); @@ -317,6 +317,8 @@ fn main() { miri_config.validate = false; } else if arg == "-Zmiri-disable-stacked-borrows" { miri_config.borrow_tracker = None; + } else if arg == "-Zmiri-tree-borrows" { + miri_config.borrow_tracker = Some(BorrowTrackerMethod::TreeBorrows); } else if arg == "-Zmiri-disable-data-race-detector" { miri_config.data_race_detector = false; miri_config.weak_memory_emulation = false; diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 9f6cbe7f3c7..ed958329f95 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -11,6 +11,7 @@ use rustc_target::abi::Size; use crate::*; pub mod stacked_borrows; +pub mod tree_borrows; pub type CallId = NonZeroU64; @@ -230,8 +231,10 @@ impl GlobalStateInner { /// Which borrow tracking method to use #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum BorrowTrackerMethod { - /// Stacked Borrows, as implemented in borrow_tracker/stacked + /// Stacked Borrows, as implemented in borrow_tracker/stacked_borrows StackedBorrows, + /// Tree borrows, as implemented in borrow_tracker/tree_borrows + TreeBorrows, } impl BorrowTrackerMethod { @@ -258,6 +261,10 @@ impl GlobalStateInner { AllocState::StackedBorrows(Box::new(RefCell::new(Stacks::new_allocation( id, alloc_size, self, kind, machine, )))), + BorrowTrackerMethod::TreeBorrows => + AllocState::TreeBorrows(Box::new(RefCell::new(Tree::new_allocation( + id, alloc_size, self, kind, machine, + )))), } } } @@ -273,6 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_retag_ptr_value(kind, val), + BorrowTrackerMethod::TreeBorrows => this.tb_retag_ptr_value(kind, val), } } @@ -285,6 +293,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_retag_place_contents(kind, place), + BorrowTrackerMethod::TreeBorrows => this.tb_retag_place_contents(kind, place), } } @@ -293,6 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_retag_return_place(), + BorrowTrackerMethod::TreeBorrows => this.tb_retag_return_place(), } } @@ -301,6 +311,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_expose_tag(alloc_id, tag), + BorrowTrackerMethod::TreeBorrows => this.tb_expose_tag(alloc_id, tag), + } + } + + fn give_pointer_debug_name( + &mut self, + ptr: Pointer<Option<Provenance>>, + nth_parent: u8, + name: &str, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; + match method { + BorrowTrackerMethod::StackedBorrows => { + this.tcx.tcx.sess.warn("Stacked Borrows does not support named pointers; `miri_pointer_name` is a no-op"); + Ok(()) + } + BorrowTrackerMethod::TreeBorrows => + this.tb_give_pointer_debug_name(ptr, nth_parent, name), + } + } + + fn print_borrow_state(&mut self, alloc_id: AllocId, show_unnamed: bool) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; + match method { + BorrowTrackerMethod::StackedBorrows => this.print_stacks(alloc_id), + BorrowTrackerMethod::TreeBorrows => this.print_tree(alloc_id, show_unnamed), } } } @@ -310,6 +348,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { pub enum AllocState { /// Data corresponding to Stacked Borrows StackedBorrows(Box<RefCell<stacked_borrows::AllocState>>), + /// Data corresponding to Tree Borrows + TreeBorrows(Box<RefCell<tree_borrows::AllocState>>), } impl machine::AllocExtra { @@ -328,6 +368,14 @@ impl machine::AllocExtra { _ => panic!("expected Stacked Borrows borrow tracking, got something else"), } } + + #[track_caller] + pub fn borrow_tracker_tb(&self) -> &RefCell<tree_borrows::AllocState> { + match self.borrow_tracker { + Some(AllocState::TreeBorrows(ref tb)) => tb, + _ => panic!("expected Tree Borrows borrow tracking, got something else"), + } + } } impl AllocState { @@ -341,6 +389,14 @@ impl AllocState { match self { AllocState::StackedBorrows(sb) => sb.borrow_mut().before_memory_read(alloc_id, prov_extra, range, machine), + AllocState::TreeBorrows(tb) => + tb.borrow_mut().before_memory_access( + AccessKind::Read, + alloc_id, + prov_extra, + range, + machine, + ), } } @@ -354,6 +410,14 @@ impl AllocState { match self { AllocState::StackedBorrows(sb) => sb.get_mut().before_memory_write(alloc_id, prov_extra, range, machine), + AllocState::TreeBorrows(tb) => + tb.get_mut().before_memory_access( + AccessKind::Write, + alloc_id, + prov_extra, + range, + machine, + ), } } @@ -367,12 +431,15 @@ impl AllocState { match self { AllocState::StackedBorrows(sb) => sb.get_mut().before_memory_deallocation(alloc_id, prov_extra, range, machine), + AllocState::TreeBorrows(tb) => + tb.get_mut().before_memory_deallocation(alloc_id, prov_extra, range, machine), } } pub fn remove_unreachable_tags(&self, tags: &FxHashSet<BorTag>) { match self { AllocState::StackedBorrows(sb) => sb.borrow_mut().remove_unreachable_tags(tags), + AllocState::TreeBorrows(tb) => tb.borrow_mut().remove_unreachable_tags(tags), } } } @@ -381,6 +448,7 @@ impl VisitTags for AllocState { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { match self { AllocState::StackedBorrows(sb) => sb.visit_tags(visit), + AllocState::TreeBorrows(tb) => tb.visit_tags(visit), } } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs new file mode 100644 index 00000000000..97bbdee1d44 --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -0,0 +1,592 @@ +use rustc_data_structures::fx::FxHashMap; + +use std::fmt; +use std::ops::Range; + +use crate::borrow_tracker::tree_borrows::{ + err_tb_ub, perms::Permission, tree::LocationState, unimap::UniIndex, +}; +use crate::borrow_tracker::{AccessKind, ProtectorKind}; +use crate::*; + +/// Some information that is irrelevant for the algorithm but very +/// convenient to know about a tag for debugging and testing. +#[derive(Clone, Debug)] +pub struct NodeDebugInfo { + /// The tag in question. + pub tag: BorTag, + /// Name(s) that were associated with this tag (comma-separated). + /// Typically the name of the variable holding the corresponding + /// pointer in the source code. + /// Helps match tag numbers to human-readable names. + pub name: Option<String>, +} +impl NodeDebugInfo { + /// New node info with a name. + pub fn new(tag: BorTag) -> Self { + Self { tag, name: None } + } + + /// Add a name to the tag. If a same tag is associated to several pointers, + /// it can have several names which will be separated by commas. + fn add_name(&mut self, name: &str) { + if let Some(ref mut prev_name) = &mut self.name { + prev_name.push(','); + prev_name.push_str(name); + } else { + self.name = Some(String::from(name)); + } + } +} + +impl fmt::Display for NodeDebugInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(ref name) = self.name { + write!(f, "{tag:?} (also named '{name}')", tag = self.tag) + } else { + write!(f, "{tag:?}", tag = self.tag) + } + } +} + +impl<'tcx> Tree { + /// Climb the tree to get the tag of a distant ancestor. + /// Allows operations on tags that are unreachable by the program + /// but still exist in the tree. Not guaranteed to perform consistently + /// if `tag-gc=1`. + fn nth_parent(&self, tag: BorTag, nth_parent: u8) -> Option<BorTag> { + let mut idx = self.tag_mapping.get(&tag).unwrap(); + for _ in 0..nth_parent { + let node = self.nodes.get(idx).unwrap(); + idx = node.parent?; + } + Some(self.nodes.get(idx).unwrap().tag) + } + + /// Debug helper: assign name to tag. + pub fn give_pointer_debug_name( + &mut self, + tag: BorTag, + nth_parent: u8, + name: &str, + ) -> InterpResult<'tcx> { + let tag = self.nth_parent(tag, nth_parent).unwrap(); + let idx = self.tag_mapping.get(&tag).unwrap(); + if let Some(node) = self.nodes.get_mut(idx) { + node.debug_info.add_name(name); + } else { + eprintln!("Tag {tag:?} (to be named '{name}') not found!"); + } + Ok(()) + } + + /// Debug helper: determines if the tree contains a tag. + pub fn is_allocation_of(&self, tag: BorTag) -> bool { + self.tag_mapping.contains_key(&tag) + } +} + +#[derive(Debug, Clone, Copy)] +pub(super) enum TransitionError { + /// This access is not allowed because some parent tag has insufficient permissions. + /// For example, if a tag is `Frozen` and encounters a child write this will + /// produce a `ChildAccessForbidden(Frozen)`. + /// This kind of error can only occur on child accesses. + ChildAccessForbidden(Permission), + /// A protector was triggered due to an invalid transition that loses + /// too much permissions. + /// For example, if a protected tag goes from `Active` to `Frozen` due + /// to a foreign write this will produce a `ProtectedTransition(Active, Frozen)`. + /// This kind of error can only occur on foreign accesses. + ProtectedTransition(Permission, Permission), + /// Cannot deallocate because some tag in the allocation is strongly protected. + /// This kind of error can only occur on deallocations. + ProtectedDealloc, +} + +/// Failures that can occur during the execution of Tree Borrows procedures. +pub(super) struct TbError<'node> { + /// What failure occurred. + pub error_kind: TransitionError, + /// The tag on which the error was triggered. + /// On protector violations, this is the tag that was protected. + /// On accesses rejected due to insufficient permissions, this is the + /// tag that lacked those permissions. + pub faulty_tag: &'node NodeDebugInfo, + /// Whether this was a Read or Write access. This field is ignored + /// when the error was triggered by a deallocation. + pub access_kind: AccessKind, + /// Which tag the access that caused this error was made through, i.e. + /// which tag was used to read/write/deallocate. + pub tag_of_access: &'node NodeDebugInfo, +} + +impl TbError<'_> { + /// Produce a UB error. + pub fn build<'tcx>(self) -> InterpErrorInfo<'tcx> { + use TransitionError::*; + err_tb_ub(match self.error_kind { + ChildAccessForbidden(perm) => { + format!( + "{kind} through {initial} is forbidden because it is a child of {current} which is {perm}.", + kind=self.access_kind, + initial=self.tag_of_access, + current=self.faulty_tag, + perm=perm, + ) + } + ProtectedTransition(start, end) => { + format!( + "{kind} through {initial} is forbidden because it is a foreign tag for {current}, which would hence change from {start} to {end}, but {current} is protected", + current=self.faulty_tag, + start=start, + end=end, + kind=self.access_kind, + initial=self.tag_of_access, + ) + } + ProtectedDealloc => { + format!( + "the allocation of {initial} also contains {current} which is strongly protected, cannot deallocate", + initial=self.tag_of_access, + current=self.faulty_tag, + ) + } + }).into() + } +} + +type S = &'static str; +/// Pretty-printing details +/// +/// Example: +/// ``` +/// DisplayFmtWrapper { +/// top: '>', +/// bot: '<', +/// warning_text: "Some tags have been hidden", +/// } +/// ``` +/// will wrap the entire text with +/// ```text +/// >>>>>>>>>>>>>>>>>>>>>>>>>> +/// Some tags have been hidden +/// +/// [ main display here ] +/// +/// <<<<<<<<<<<<<<<<<<<<<<<<<< +/// ``` +struct DisplayFmtWrapper { + /// Character repeated to make the upper border. + top: char, + /// Character repeated to make the lower border. + bot: char, + /// Warning about some tags (unnamed) being hidden. + warning_text: S, +} + +/// Formating of the permissions on each range. +/// +/// Example: +/// ``` +/// DisplayFmtPermission { +/// open: "[", +/// sep: "|", +/// close: "]", +/// uninit: "___", +/// range_sep: "..", +/// } +/// ``` +/// will show each permission line as +/// ```text +/// 0.. 1.. 2.. 3.. 4.. 5 +/// [Act|Res|Frz|Dis|___] +/// ``` +struct DisplayFmtPermission { + /// Text that starts the permission block. + open: S, + /// Text that separates permissions on different ranges. + sep: S, + /// Text that ends the permission block. + close: S, + /// Text to show when a permission is not initialized. + /// Should have the same width as a `Permission`'s `.short_name()`, i.e. + /// 3 if using the `Res/Act/Frz/Dis` notation. + uninit: S, + /// Text to separate the `start` and `end` values of a range. + range_sep: S, +} + +/// Formating of the tree structure. +/// +/// Example: +/// ``` +/// DisplayFmtPadding { +/// join_middle: "|-", +/// join_last: "'-", +/// join_haschild: "-+-", +/// join_default: "---", +/// indent_middle: "| ", +/// indent_last: " ", +/// } +/// ``` +/// will show the tree as +/// ```text +/// -+- root +/// |--+- a +/// | '--+- b +/// | '---- c +/// |--+- d +/// | '---- e +/// '---- f +/// ``` +struct DisplayFmtPadding { + /// Connector for a child other than the last. + join_middle: S, + /// Connector for the last child. Should have the same width as `join_middle`. + join_last: S, + /// Connector for a node that itself has a child. + join_haschild: S, + /// Connector for a node that does not have a child. Should have the same width + /// as `join_haschild`. + join_default: S, + /// Indentation when there is a next child. + indent_middle: S, + /// Indentation for the last child. + indent_last: S, +} +/// How to show whether a location has been accessed +/// +/// Example: +/// ``` +/// DisplayFmtAccess { +/// yes: " ", +/// no: "?", +/// meh: "_", +/// } +/// ``` +/// will show states as +/// ```text +/// Act +/// ?Res +/// ____ +/// ``` +struct DisplayFmtAccess { + /// Used when `State.initialized = true`. + yes: S, + /// Used when `State.initialized = false`. + /// Should have the same width as `yes`. + no: S, + /// Used when there is no `State`. + /// Should have the same width as `yes`. + meh: S, +} + +/// All parameters to determine how the tree is formated. +struct DisplayFmt { + wrapper: DisplayFmtWrapper, + perm: DisplayFmtPermission, + padding: DisplayFmtPadding, + accessed: DisplayFmtAccess, +} +impl DisplayFmt { + /// Print the permission with the format + /// ` Res`/` Re*`/` Act`/` Frz`/` Dis` for accessed locations + /// and `?Res`/`?Re*`/`?Act`/`?Frz`/`?Dis` for unaccessed locations. + fn print_perm(&self, perm: Option<LocationState>) -> String { + if let Some(perm) = perm { + format!( + "{ac}{st}", + ac = if perm.is_initialized() { self.accessed.yes } else { self.accessed.no }, + st = perm.permission().short_name(), + ) + } else { + format!("{}{}", self.accessed.meh, self.perm.uninit) + } + } + + /// Print the tag with the format `<XYZ>` if the tag is unnamed, + /// and `<XYZ=name>` if the tag is named. + fn print_tag(&self, tag: BorTag, name: &Option<String>) -> String { + let printable_tag = tag.get(); + if let Some(name) = name { + format!("<{printable_tag}={name}>") + } else { + format!("<{printable_tag}>") + } + } + + /// Print extra text if the tag has a protector. + fn print_protector(&self, protector: Option<&ProtectorKind>) -> &'static str { + protector + .map(|p| { + match *p { + ProtectorKind::WeakProtector => " Weakly protected", + ProtectorKind::StrongProtector => " Strongly protected", + } + }) + .unwrap_or("") + } +} + +/// Track the indentation of the tree. +struct DisplayIndent { + curr: String, +} +impl DisplayIndent { + fn new() -> Self { + Self { curr: " ".to_string() } + } + + /// Increment the indentation by one. Note: need to know if this + /// is the last child or not because the presence of other children + /// changes the way the indentation is shown. + fn increment(&mut self, formatter: &DisplayFmt, is_last: bool) { + self.curr.push_str(if is_last { + formatter.padding.indent_last + } else { + formatter.padding.indent_middle + }); + } + + /// Pop the last level of indentation. + fn decrement(&mut self, formatter: &DisplayFmt) { + for _ in 0..formatter.padding.indent_last.len() { + let _ = self.curr.pop(); + } + } + + /// Print the current indentation. + fn write(&self, s: &mut String) { + s.push_str(&self.curr); + } +} + +/// Repeat a character a number of times. +fn char_repeat(c: char, n: usize) -> String { + std::iter::once(c).cycle().take(n).collect::<String>() +} + +/// Extracted information from the tree, in a form that is readily accessible +/// for printing. I.e. resolve parent-child pointers into an actual tree, +/// zip permissions with their tag, remove wrappers, stringify data. +struct DisplayRepr { + tag: BorTag, + name: Option<String>, + rperm: Vec<Option<LocationState>>, + children: Vec<DisplayRepr>, +} + +impl DisplayRepr { + fn from(tree: &Tree, show_unnamed: bool) -> Option<Self> { + let mut v = Vec::new(); + extraction_aux(tree, tree.root, show_unnamed, &mut v); + let Some(root) = v.pop() else { + if show_unnamed { + unreachable!("This allocation contains no tags, not even a root. This should not happen."); + } + eprintln!("This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."); + return None; + }; + assert!(v.is_empty()); + return Some(root); + + fn extraction_aux( + tree: &Tree, + idx: UniIndex, + show_unnamed: bool, + acc: &mut Vec<DisplayRepr>, + ) { + let node = tree.nodes.get(idx).unwrap(); + let name = node.debug_info.name.clone(); + let children_sorted = { + let mut children = node.children.iter().cloned().collect::<Vec<_>>(); + children.sort_by_key(|idx| tree.nodes.get(*idx).unwrap().tag); + children + }; + if !show_unnamed && name.is_none() { + // We skip this node + for child_idx in children_sorted { + extraction_aux(tree, child_idx, show_unnamed, acc); + } + } else { + // We take this node + let rperm = tree + .rperms + .iter_all() + .map(move |(_offset, perms)| { + let perm = perms.get(idx); + perm.cloned() + }) + .collect::<Vec<_>>(); + let mut children = Vec::new(); + for child_idx in children_sorted { + extraction_aux(tree, child_idx, show_unnamed, &mut children); + } + acc.push(DisplayRepr { tag: node.tag, name, rperm, children }); + } + } + } + fn print( + &self, + fmt: &DisplayFmt, + indenter: &mut DisplayIndent, + protected_tags: &FxHashMap<BorTag, ProtectorKind>, + ranges: Vec<Range<u64>>, + print_warning: bool, + ) { + let mut block = Vec::new(); + // Push the header and compute the required paddings for the body. + // Header looks like this: `0.. 1.. 2.. 3.. 4.. 5.. 6.. 7.. 8`, + // and is properly aligned with the `|` of the body. + let (range_header, range_padding) = { + let mut header_top = String::new(); + header_top.push_str("0.."); + let mut padding = Vec::new(); + for (i, range) in ranges.iter().enumerate() { + if i > 0 { + header_top.push_str(fmt.perm.range_sep); + } + let s = range.end.to_string(); + let l = s.chars().count() + fmt.perm.range_sep.chars().count(); + { + let target_len = + fmt.perm.uninit.chars().count() + fmt.accessed.yes.chars().count() + 1; + let tot_len = target_len.max(l); + let header_top_pad_len = target_len.saturating_sub(l); + let body_pad_len = tot_len.saturating_sub(target_len); + header_top.push_str(&format!("{}{}", char_repeat(' ', header_top_pad_len), s)); + padding.push(body_pad_len); + } + } + ([header_top], padding) + }; + for s in range_header { + block.push(s); + } + // This is the actual work + print_aux( + self, + &range_padding, + fmt, + indenter, + protected_tags, + true, /* root _is_ the last child */ + &mut block, + ); + // Then it's just prettifying it with a border of dashes. + { + let wr = &fmt.wrapper; + let max_width = { + let block_width = block.iter().map(|s| s.chars().count()).max().unwrap(); + if print_warning { + block_width.max(wr.warning_text.chars().count()) + } else { + block_width + } + }; + eprintln!("{}", char_repeat(wr.top, max_width)); + if print_warning { + eprintln!("{}", wr.warning_text,); + } + for line in block { + eprintln!("{line}"); + } + eprintln!("{}", char_repeat(wr.bot, max_width)); + } + + // Here is the function that does the heavy lifting + fn print_aux( + tree: &DisplayRepr, + padding: &[usize], + fmt: &DisplayFmt, + indent: &mut DisplayIndent, + protected_tags: &FxHashMap<BorTag, ProtectorKind>, + is_last_child: bool, + acc: &mut Vec<String>, + ) { + let mut line = String::new(); + // Format the permissions on each range. + // Looks like `| Act| Res| Res| Act|`. + line.push_str(fmt.perm.open); + for (i, (perm, &pad)) in tree.rperm.iter().zip(padding.iter()).enumerate() { + if i > 0 { + line.push_str(fmt.perm.sep); + } + let show_perm = fmt.print_perm(*perm); + line.push_str(&format!("{}{}", char_repeat(' ', pad), show_perm)); + } + line.push_str(fmt.perm.close); + // Format the tree structure. + // Main difficulty is handling the indentation properly. + indent.write(&mut line); + { + // padding + line.push_str(if is_last_child { + fmt.padding.join_last + } else { + fmt.padding.join_middle + }); + line.push_str(fmt.padding.join_default); + line.push_str(if tree.children.is_empty() { + fmt.padding.join_default + } else { + fmt.padding.join_haschild + }); + line.push_str(fmt.padding.join_default); + line.push_str(fmt.padding.join_default); + } + line.push_str(&fmt.print_tag(tree.tag, &tree.name)); + let protector = protected_tags.get(&tree.tag); + line.push_str(fmt.print_protector(protector)); + // Push the line to the accumulator then recurse. + acc.push(line); + let nb_children = tree.children.len(); + for (i, child) in tree.children.iter().enumerate() { + indent.increment(fmt, is_last_child); + print_aux(child, padding, fmt, indent, protected_tags, i + 1 == nb_children, acc); + indent.decrement(fmt); + } + } + } +} + +const DEFAULT_FORMATTER: DisplayFmt = DisplayFmt { + wrapper: DisplayFmtWrapper { + top: '─', + bot: '─', + warning_text: "Warning: this tree is indicative only. Some tags may have been hidden.", + }, + perm: DisplayFmtPermission { open: "|", sep: "|", close: "|", uninit: "---", range_sep: ".." }, + padding: DisplayFmtPadding { + join_middle: "├", + join_last: "â””", + indent_middle: "│ ", + indent_last: " ", + join_haschild: "┬", + join_default: "─", + }, + accessed: DisplayFmtAccess { yes: " ", no: "?", meh: "-" }, +}; + +impl<'tcx> Tree { + /// Display the contents of the tree. + pub fn print_tree( + &self, + protected_tags: &FxHashMap<BorTag, ProtectorKind>, + show_unnamed: bool, + ) -> InterpResult<'tcx> { + let mut indenter = DisplayIndent::new(); + let ranges = self.rperms.iter_all().map(|(range, _perms)| range).collect::<Vec<_>>(); + if let Some(repr) = DisplayRepr::from(self, show_unnamed) { + repr.print( + &DEFAULT_FORMATTER, + &mut indenter, + protected_tags, + ranges, + /* print warning message about tags not shown */ !show_unnamed, + ); + } + Ok(()) + } +} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs new file mode 100644 index 00000000000..2297ceb1259 --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -0,0 +1,539 @@ +use log::trace; + +use rustc_target::abi::{Abi, Size}; + +use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields}; +use rustc_middle::{ + mir::{Mutability, RetagKind}, + ty::{ + self, + layout::{HasParamEnv, LayoutOf}, + Ty, + }, +}; + +use crate::*; + +mod diagnostics; +mod perms; +mod tree; +mod unimap; +use perms::Permission; +pub use tree::Tree; + +pub type AllocState = Tree; + +pub fn err_tb_ub<'tcx>(msg: String) -> InterpError<'tcx> { + err_machine_stop!(TerminationInfo::TreeBorrowsUb { msg }) +} + +impl<'tcx> Tree { + /// Create a new allocation, i.e. a new tree + pub fn new_allocation( + id: AllocId, + size: Size, + state: &mut GlobalStateInner, + _kind: MemoryKind<machine::MiriMemoryKind>, + machine: &MiriMachine<'_, 'tcx>, + ) -> Self { + let tag = state.base_ptr_tag(id, machine); // Fresh tag for the root + Tree::new(tag, size) + } + + /// Check that an access on the entire range is permitted, and update + /// the tree. + pub fn before_memory_access( + &mut self, + access_kind: AccessKind, + alloc_id: AllocId, + prov: ProvenanceExtra, + range: AllocRange, + machine: &MiriMachine<'_, 'tcx>, + ) -> InterpResult<'tcx> { + trace!( + "{} with tag {:?}: {:?}, size {}", + access_kind, + prov, + Pointer::new(alloc_id, range.start), + range.size.bytes(), + ); + // TODO: for now we bail out on wildcard pointers. Eventually we should + // handle them as much as we can. + let tag = match prov { + ProvenanceExtra::Concrete(tag) => tag, + ProvenanceExtra::Wildcard => return Ok(()), + }; + let global = machine.borrow_tracker.as_ref().unwrap(); + self.perform_access(access_kind, tag, range, global) + } + + /// Check that this pointer has permission to deallocate this range. + pub fn before_memory_deallocation( + &mut self, + _alloc_id: AllocId, + prov: ProvenanceExtra, + range: AllocRange, + machine: &MiriMachine<'_, 'tcx>, + ) -> InterpResult<'tcx> { + // TODO: for now we bail out on wildcard pointers. Eventually we should + // handle them as much as we can. + let tag = match prov { + ProvenanceExtra::Concrete(tag) => tag, + ProvenanceExtra::Wildcard => return Ok(()), + }; + let global = machine.borrow_tracker.as_ref().unwrap(); + self.dealloc(tag, range, global) + } + + pub fn expose_tag(&mut self, _tag: BorTag) { + // TODO + } +} + +/// Policy for a new borrow. +#[derive(Debug, Clone, Copy)] +struct NewPermission { + /// Whether this borrow requires a read access on its parent. + /// `perform_read_access` is `true` for all pointers marked `dereferenceable`. + perform_read_access: bool, + /// Which permission should the pointer start with. + initial_state: Permission, + /// Whether this pointer is part of the arguments of a function call. + /// `protector` is `Some(_)` for all pointers marked `noalias`. + protector: Option<ProtectorKind>, +} + +impl<'tcx> NewPermission { + /// Determine NewPermission of the reference from the type of the pointee. + fn from_ref_ty( + pointee: Ty<'tcx>, + mutability: Mutability, + kind: RetagKind, + cx: &crate::MiriInterpCx<'_, 'tcx>, + ) -> Option<Self> { + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env()); + let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env()); + let initial_state = match mutability { + Mutability::Mut if ty_is_unpin => Permission::new_unique_2phase(ty_is_freeze), + Mutability::Not if ty_is_freeze => Permission::new_frozen(), + // Raw pointers never enter this function so they are not handled. + // However raw pointers are not the only pointers that take the parent + // tag, this also happens for `!Unpin` `&mut`s and interior mutable + // `&`s, which are excluded above. + _ => return None, + }; + // This field happens to be redundant since right now we always do a read, + // but it could be useful in the future. + let perform_read_access = true; + + let protector = (kind == RetagKind::FnEntry).then_some(ProtectorKind::StrongProtector); + Some(Self { perform_read_access, initial_state, protector }) + } + + // Boxes are not handled by `from_ref_ty`, they need special behavior + // implemented here. + fn from_box_ty( + ty: Ty<'tcx>, + kind: RetagKind, + cx: &crate::MiriInterpCx<'_, 'tcx>, + ) -> Option<Self> { + let pointee = ty.builtin_deref(true).unwrap().ty; + pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| { + // Regular `Unpin` box, give it `noalias` but only a weak protector + // because it is valid to deallocate it within the function. + let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.param_env()); + Self { + perform_read_access: true, + initial_state: Permission::new_unique_2phase(ty_is_freeze), + protector: (kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector), + } + }) + } +} + +/// Retagging/reborrowing. +/// Policy on which permission to grant to each pointer should be left to +/// the implementation of NewPermission. +impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx> + for crate::MiriInterpCx<'mir, 'tcx> +{ +} +trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Returns the `AllocId` the reborrow was done in, if there is some actual + /// memory associated with this pointer. Returns `None` if there is no actual + /// memory allocated. Also checks that the reborrow of size `ptr_size` is + /// within bounds of the allocation. + /// + /// Also returns the tag that the pointer should get, which is essentially + /// `if new_perm.is_some() { new_tag } else { parent_tag }` along with + /// some logging (always) and fake reads (if `new_perm` is + /// `Some(NewPermission { perform_read_access: true }`). + fn tb_reborrow( + &mut self, + place: &MPlaceTy<'tcx, Provenance>, // parent tag extracted from here + ptr_size: Size, + new_perm: Option<NewPermission>, + new_tag: BorTag, + ) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> { + let this = self.eval_context_mut(); + + // It is crucial that this gets called on all code paths, to ensure we track tag creation. + let log_creation = |this: &MiriInterpCx<'mir, 'tcx>, + loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag + -> InterpResult<'tcx> { + let global = this.machine.borrow_tracker.as_ref().unwrap().borrow(); + let ty = place.layout.ty; + if global.tracked_pointer_tags.contains(&new_tag) { + let kind_str = format!("{new_perm:?} (pointee type {ty})"); + this.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag( + new_tag.inner(), + Some(kind_str), + loc.map(|(alloc_id, base_offset, orig_tag)| (alloc_id, alloc_range(base_offset, ptr_size), orig_tag)), + )); + } + drop(global); // don't hold that reference any longer than we have to + Ok(()) + }; + + let (alloc_id, base_offset, parent_prov) = if ptr_size > Size::ZERO { + this.ptr_get_alloc_id(place.ptr)? + } else { + match this.ptr_try_get_alloc_id(place.ptr) { + Ok(data) => data, + Err(_) => { + // This pointer doesn't come with an AllocId, so there's no + // memory to do retagging in. + trace!( + "reborrow of size 0: reference {:?} derived from {:?} (pointee {})", + new_tag, + place.ptr, + place.layout.ty, + ); + log_creation(this, None)?; + return Ok(None); + } + } + }; + let orig_tag = match parent_prov { + ProvenanceExtra::Wildcard => return Ok(None), // TODO: handle wildcard pointers + ProvenanceExtra::Concrete(tag) => tag, + }; + + // Protection against trying to get a reference to a vtable: + // vtables do not have an alloc_extra so the call to + // `get_alloc_extra` that follows fails. + let (alloc_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); + if ptr_size == Size::ZERO && !matches!(alloc_kind, AllocKind::LiveData) { + return Ok(Some((alloc_id, orig_tag))); + } + + log_creation(this, Some((alloc_id, base_offset, parent_prov)))?; + + // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). + if base_offset + ptr_size > alloc_size { + throw_ub!(PointerOutOfBounds { + alloc_id, + alloc_size, + ptr_offset: this.target_usize_to_isize(base_offset.bytes()), + ptr_size, + msg: CheckInAllocMsg::InboundsTest + }); + } + + trace!( + "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}", + new_tag, + orig_tag, + place.layout.ty, + Pointer::new(alloc_id, base_offset), + ptr_size.bytes() + ); + + let Some(new_perm) = new_perm else { return Ok(Some((alloc_id, orig_tag))); }; + + if let Some(protect) = new_perm.protector { + // We register the protection in two different places. + // This makes creating a protector slower, but checking whether a tag + // is protected faster. + this.frame_mut().extra.borrow_tracker.as_mut().unwrap().protected_tags.push(new_tag); + this.machine + .borrow_tracker + .as_mut() + .expect("We should have borrow tracking data") + .get_mut() + .protected_tags + .insert(new_tag, protect); + } + + let alloc_extra = this.get_alloc_extra(alloc_id)?; + let range = alloc_range(base_offset, ptr_size); + let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); + + if new_perm.perform_read_access { + // Count this reborrow as a read access + let global = &this.machine.borrow_tracker.as_ref().unwrap(); + tree_borrows.perform_access(AccessKind::Read, orig_tag, range, global)?; + if let Some(data_race) = alloc_extra.data_race.as_ref() { + data_race.read(alloc_id, range, &this.machine)?; + } + } + + // Record the parent-child pair in the tree. + tree_borrows.new_child(orig_tag, new_tag, new_perm.initial_state, range)?; + Ok(Some((alloc_id, new_tag))) + } + + /// Retags an indidual pointer, returning the retagged version. + fn tb_retag_reference( + &mut self, + val: &ImmTy<'tcx, Provenance>, + new_perm: Option<NewPermission>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + let this = self.eval_context_mut(); + // We want a place for where the ptr *points to*, so we get one. + let place = this.ref_to_mplace(val)?; + + // Get a lower bound of the size of this place. + // (When `extern type` are involved, use the size of the known prefix.) + let size = this + .size_and_align_of_mplace(&place)? + .map(|(size, _)| size) + .unwrap_or(place.layout.size); + + // This new tag is not guaranteed to actually be used. + // + // If you run out of tags, consider the following optimization: adjust `tb_reborrow` + // so that rather than taking as input a fresh tag and deciding whether it uses this + // one or the parent it instead just returns whether a new tag should be created. + // This will avoid creating tags than end up never being used. + let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr(); + + // Compute the actual reborrow. + let reborrowed = this.tb_reborrow(&place, size, new_perm, new_tag)?; + + // Adjust pointer. + let new_place = place.map_provenance(|p| { + p.map(|prov| { + match reborrowed { + Some((alloc_id, actual_tag)) => { + // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one. + // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation. + Provenance::Concrete { alloc_id, tag: actual_tag } + } + None => { + // Looks like this has to stay a wildcard pointer. + assert!(matches!(prov, Provenance::Wildcard)); + Provenance::Wildcard + } + } + }) + }); + + // Return new pointer. + Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Retag a pointer. References are passed to `from_ref_ty` and + /// raw pointers are never reborrowed. + fn tb_retag_ptr_value( + &mut self, + kind: RetagKind, + val: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + let this = self.eval_context_mut(); + let new_perm = if let &ty::Ref(_, pointee, mutability) = val.layout.ty.kind() { + NewPermission::from_ref_ty(pointee, mutability, kind, this) + } else { + None + }; + this.tb_retag_reference(val, new_perm) + } + + /// Retag all pointers that are stored in this place. + fn tb_retag_place_contents( + &mut self, + kind: RetagKind, + place: &PlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields; + let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; + return visitor.visit_value(place); + + // The actual visitor. + struct RetagVisitor<'ecx, 'mir, 'tcx> { + ecx: &'ecx mut MiriInterpCx<'mir, 'tcx>, + kind: RetagKind, + retag_fields: RetagFields, + } + impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> { + #[inline(always)] // yes this helps in our benchmarks + fn retag_ptr_inplace( + &mut self, + place: &PlaceTy<'tcx, Provenance>, + new_perm: Option<NewPermission>, + ) -> InterpResult<'tcx> { + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; + let val = self.ecx.tb_retag_reference(&val, new_perm)?; + self.ecx.write_immediate(*val, place)?; + Ok(()) + } + } + impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>> + for RetagVisitor<'ecx, 'mir, 'tcx> + { + type V = PlaceTy<'tcx, Provenance>; + + #[inline(always)] + fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> { + self.ecx + } + + fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx); + self.retag_ptr_inplace(place, new_perm) + } + + fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + // If this place is smaller than a pointer, we know that it can't contain any + // pointers we need to retag, so we can stop recursion early. + // This optimization is crucial for ZSTs, because they can contain way more fields + // than we can ever visit. + if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() { + return Ok(()); + } + + // Check the type of this value to see what to do with it (retag, or recurse). + match place.layout.ty.kind() { + &ty::Ref(_, pointee, mutability) => { + let new_perm = + NewPermission::from_ref_ty(pointee, mutability, self.kind, self.ecx); + self.retag_ptr_inplace(place, new_perm)?; + } + ty::RawPtr(_) => { + // We definitely do *not* want to recurse into raw pointers -- wide raw + // pointers have fields, and for dyn Trait pointees those can have reference + // type! + // We also do not want to reborrow them. + } + ty::Adt(adt, _) if adt.is_box() => { + // Recurse for boxes, they require some tricky handling and will end up in `visit_box` above. + // (Yes this means we technically also recursively retag the allocator itself + // even if field retagging is not enabled. *shrug*) + self.walk_value(place)?; + } + _ => { + // Not a reference/pointer/box. Only recurse if configured appropriately. + let recurse = match self.retag_fields { + RetagFields::No => false, + RetagFields::Yes => true, + RetagFields::OnlyScalar => { + // Matching `ArgAbi::new` at the time of writing, only fields of + // `Scalar` and `ScalarPair` ABI are considered. + matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) + } + }; + if recurse { + self.walk_value(place)?; + } + } + } + + Ok(()) + } + } + } + + /// After a stack frame got pushed, retag the return place so that we are sure + /// it does not alias with anything. + /// + /// This is a HACK because there is nothing in MIR that would make the retag + /// explicit. Also see <https://github.com/rust-lang/rust/issues/71117>. + fn tb_retag_return_place(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + //this.debug_hint_location(); + let return_place = &this.frame().return_place; + if return_place.layout.is_zst() { + // There may not be any memory here, nothing to do. + return Ok(()); + } + // We need this to be in-memory to use tagged pointers. + let return_place = this.force_allocation(&return_place.clone())?; + + // We have to turn the place into a pointer to use the existing code. + // (The pointer type does not matter, so we use a raw pointer.) + let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; + let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); + // Reborrow it. With protection! That is part of the point. + // FIXME: do we truly want a 2phase borrow here? + let new_perm = Some(NewPermission { + initial_state: Permission::new_unique_2phase(/*freeze*/ false), + perform_read_access: true, + protector: Some(ProtectorKind::StrongProtector), + }); + let val = this.tb_retag_reference(&val, new_perm)?; + // And use reborrowed pointer for return place. + let return_place = this.ref_to_mplace(&val)?; + this.frame_mut().return_place = return_place.into(); + + Ok(()) + } + + /// Mark the given tag as exposed. It was found on a pointer with the given AllocId. + fn tb_expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + // Function pointers and dead objects don't have an alloc_extra so we ignore them. + // This is okay because accessing them is UB anyway, no need for any Tree Borrows checks. + // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! + let (_size, _align, kind) = this.get_alloc_info(alloc_id); + match kind { + AllocKind::LiveData => { + // This should have alloc_extra data, but `get_alloc_extra` can still fail + // if converting this alloc_id from a global to a local one + // uncovers a non-supported `extern static`. + let alloc_extra = this.get_alloc_extra(alloc_id)?; + trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); + alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag); + } + AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { + // No tree borrows on these allocations. + } + } + Ok(()) + } + + /// Display the tree. + fn print_tree(&mut self, alloc_id: AllocId, show_unnamed: bool) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let alloc_extra = this.get_alloc_extra(alloc_id)?; + let tree_borrows = alloc_extra.borrow_tracker_tb().borrow(); + let borrow_tracker = &this.machine.borrow_tracker.as_ref().unwrap().borrow(); + tree_borrows.print_tree(&borrow_tracker.protected_tags, show_unnamed) + } + + /// Give a name to the pointer, usually the name it has in the source code (for debugging). + /// The name given is `name` and the pointer that receives it is the `nth_parent` + /// of `ptr` (with 0 representing `ptr` itself) + fn tb_give_pointer_debug_name( + &mut self, + ptr: Pointer<Option<Provenance>>, + nth_parent: u8, + name: &str, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (tag, alloc_id) = match ptr.provenance { + Some(Provenance::Concrete { tag, alloc_id }) => (tag, alloc_id), + _ => { + eprintln!("Can't give the name {name} to Wildcard pointer"); + return Ok(()); + } + }; + let alloc_extra = this.get_alloc_extra(alloc_id)?; + let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); + tree_borrows.give_pointer_debug_name(tag, nth_parent, name) + } +} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs new file mode 100644 index 00000000000..04b8e1df576 --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -0,0 +1,307 @@ +use std::cmp::{Ordering, PartialOrd}; +use std::fmt; + +use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness; +use crate::borrow_tracker::AccessKind; + +/// The activation states of a pointer +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum PermissionPriv { + /// represents: a local reference that has not yet been written to; + /// allows: child reads, foreign reads, foreign writes if type is freeze; + /// rejects: child writes (Active), foreign writes (Disabled, except if type is not freeze). + /// special case: behaves differently when protected to adhere more closely to noalias + Reserved { ty_is_freeze: bool }, + /// represents: a unique pointer; + /// allows: child reads, child writes; + /// rejects: foreign reads (Frozen), foreign writes (Disabled). + Active, + /// represents: a shared pointer; + /// allows: all read accesses; + /// rejects child writes (UB), foreign writes (Disabled). + Frozen, + /// represents: a dead pointer; + /// allows: all foreign accesses; + /// rejects: all child accesses (UB). + Disabled, +} +use PermissionPriv::*; + +impl PartialOrd for PermissionPriv { + /// PermissionPriv is ordered as follows: + /// - Reserved(_) < Active < Frozen < Disabled; + /// - different kinds of `Reserved` (with or without interior mutability) + /// are incomparable to each other. + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + use Ordering::*; + Some(match (self, other) { + (a, b) if a == b => Equal, + (Disabled, _) => Greater, + (_, Disabled) => Less, + (Frozen, _) => Greater, + (_, Frozen) => Less, + (Active, _) => Greater, + (_, Active) => Less, + (Reserved { .. }, Reserved { .. }) => return None, + }) + } +} + +/// This module controls how each permission individually reacts to an access. +/// Although these functions take `protected` as an argument, this is NOT because +/// we check protector violations here, but because some permissions behave differently +/// when protected. +mod transition { + use super::*; + /// A child node was read-accessed: UB on Disabled, noop on the rest. + fn child_read(state: PermissionPriv, _protected: bool) -> Option<PermissionPriv> { + Some(match state { + Disabled => return None, + // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read + // accesses, since the data is not being mutated. Hence the `{ .. }` + readable @ (Reserved { .. } | Active | Frozen) => readable, + }) + } + + /// A non-child node was read-accessed: noop on non-protected Reserved, advance to Frozen otherwise. + fn foreign_read(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> { + use Option::*; + Some(match state { + // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read + // accesses, since the data is not being mutated. Hence the `{ .. }` + res @ Reserved { .. } if !protected => res, + Reserved { .. } => Frozen, // protected reserved + Active => Frozen, + non_writeable @ (Frozen | Disabled) => non_writeable, + }) + } + + /// A child node was write-accessed: `Reserved` must become `Active` to obtain + /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB. + fn child_write(state: PermissionPriv, _protected: bool) -> Option<PermissionPriv> { + Some(match state { + // A write always activates the 2-phase borrow, even with interior + // mutability + Reserved { .. } | Active => Active, + Frozen | Disabled => return None, + }) + } + + /// A non-child node was write-accessed: this makes everything `Disabled` except for + /// non-protected interior mutable `Reserved` which stay the same. + fn foreign_write(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> { + Some(match state { + cell @ Reserved { ty_is_freeze: false } if !protected => cell, + _ => Disabled, + }) + } + + /// Dispatch handler depending on the kind of access and its position. + pub(super) fn perform_access( + kind: AccessKind, + rel_pos: AccessRelatedness, + child: PermissionPriv, + protected: bool, + ) -> Option<PermissionPriv> { + match (kind, rel_pos.is_foreign()) { + (AccessKind::Write, true) => foreign_write(child, protected), + (AccessKind::Read, true) => foreign_read(child, protected), + (AccessKind::Write, false) => child_write(child, protected), + (AccessKind::Read, false) => child_read(child, protected), + } + } +} + +impl PermissionPriv { + /// Determines whether a transition that occured is compatible with the presence + /// of a Protector. This is not included in the `transition` functions because + /// it would distract from the few places where the transition is modified + /// because of a protector, but not forbidden. + fn protector_allows_transition(self, new: Self) -> bool { + match (self, new) { + _ if self == new => true, + // It is always a protector violation to not be readable anymore + (_, Disabled) => false, + // In the case of a `Reserved` under a protector, both transitions + // `Reserved => Active` and `Reserved => Frozen` can legitimately occur. + // The first is standard (Child Write), the second is for Foreign Writes + // on protected Reserved where we must ensure that the pointer is not + // written to in the future. + (Reserved { .. }, Active) | (Reserved { .. }, Frozen) => true, + // This pointer should have stayed writeable for the whole function + (Active, Frozen) => false, + _ => unreachable!("Transition from {self:?} to {new:?} should never be possible"), + } + } +} + +/// Public interface to the state machine that controls read-write permissions. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Permission(PermissionPriv); + +impl fmt::Display for Permission { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self.0 { + PermissionPriv::Reserved { .. } => "Reserved", + PermissionPriv::Active => "Active", + PermissionPriv::Frozen => "Frozen", + PermissionPriv::Disabled => "Disabled", + } + ) + } +} + +impl Permission { + /// Default initial permission of the root of a new tree. + pub fn new_root() -> Self { + Self(Active) + } + + /// Default initial permission of a reborrowed mutable reference. + pub fn new_unique_2phase(ty_is_freeze: bool) -> Self { + Self(Reserved { ty_is_freeze }) + } + + /// Default initial permission of a reborrowed shared reference + pub fn new_frozen() -> Self { + Self(Frozen) + } + + /// Pretty-printing. Needs to be here and not in diagnostics.rs + /// because `Self` is private. + pub fn short_name(self) -> &'static str { + // Make sure there are all of the same length as each other + // and also as `diagnostics::DisplayFmtPermission.uninit` otherwise + // alignment will be incorrect. + match self.0 { + Reserved { ty_is_freeze: true } => "Res", + Reserved { ty_is_freeze: false } => "Re*", + Active => "Act", + Frozen => "Frz", + Disabled => "Dis", + } + } + + /// Check that there are no complaints from a possible protector. + /// + /// Note: this is not in charge of checking that there *is* a protector, + /// it should be used as + /// ``` + /// let no_protector_error = if is_protected(tag) { + /// old_perm.protector_allows_transition(new_perm) + /// }; + /// ``` + pub fn protector_allows_transition(self, new: Self) -> bool { + self.0.protector_allows_transition(new.0) + } + + /// Apply the transition to the inner PermissionPriv. + pub fn perform_access( + kind: AccessKind, + rel_pos: AccessRelatedness, + old_perm: Self, + protected: bool, + ) -> Option<Self> { + let old_state = old_perm.0; + transition::perform_access(kind, rel_pos, old_state, protected).map(Self) + } +} + +#[cfg(test)] +mod propagation_optimization_checks { + pub use super::*; + + mod util { + pub use super::*; + impl PermissionPriv { + /// Enumerate all states + pub fn all() -> impl Iterator<Item = PermissionPriv> { + vec![ + Active, + Reserved { ty_is_freeze: true }, + Reserved { ty_is_freeze: false }, + Frozen, + Disabled, + ] + .into_iter() + } + } + + impl AccessKind { + /// Enumerate all AccessKind. + pub fn all() -> impl Iterator<Item = AccessKind> { + use AccessKind::*; + [Read, Write].into_iter() + } + } + + impl AccessRelatedness { + /// Enumerate all relative positions + pub fn all() -> impl Iterator<Item = AccessRelatedness> { + use AccessRelatedness::*; + [This, StrictChildAccess, AncestorAccess, DistantAccess].into_iter() + } + } + } + + #[test] + // For any kind of access, if we do it twice the second should be a no-op. + // Even if the protector has disappeared. + fn all_transitions_idempotent() { + use transition::*; + for old in PermissionPriv::all() { + for (old_protected, new_protected) in [(true, true), (true, false), (false, false)] { + for access in AccessKind::all() { + for rel_pos in AccessRelatedness::all() { + if let Some(new) = perform_access(access, rel_pos, old, old_protected) { + assert_eq!( + new, + perform_access(access, rel_pos, new, new_protected).unwrap() + ); + } + } + } + } + } + } + + #[test] + fn foreign_read_is_noop_after_write() { + use transition::*; + let old_access = AccessKind::Write; + let new_access = AccessKind::Read; + for old in PermissionPriv::all() { + for (old_protected, new_protected) in [(true, true), (true, false), (false, false)] { + for rel_pos in AccessRelatedness::all().filter(|rel| rel.is_foreign()) { + if let Some(new) = perform_access(old_access, rel_pos, old, old_protected) { + assert_eq!( + new, + perform_access(new_access, rel_pos, new, new_protected).unwrap() + ); + } + } + } + } + } + + #[test] + // Check that all transitions are consistent with the order on PermissionPriv, + // i.e. Reserved -> Active -> Frozen -> Disabled + fn access_transitions_progress_increasing() { + use transition::*; + for old in PermissionPriv::all() { + for protected in [true, false] { + for access in AccessKind::all() { + for rel_pos in AccessRelatedness::all() { + if let Some(new) = perform_access(access, rel_pos, old, protected) { + assert!(old <= new); + } + } + } + } + } + } +} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs new file mode 100644 index 00000000000..86416a0eb1b --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -0,0 +1,554 @@ +//! In this file we handle the "Tree" part of Tree Borrows, i.e. all tree +//! traversal functions, optimizations to trim branches, and keeping track of +//! the relative position of the access to each node being updated. This of course +//! also includes the definition of the tree structure. +//! +//! Functions here manipulate permissions but are oblivious to them: as +//! the internals of `Permission` are private, the update process is a black +//! box. All we need to know here are +//! - the fact that updates depend only on the old state, the status of protectors, +//! and the relative position of the access; +//! - idempotency properties asserted in `perms.rs` (for optimizations) + +use smallvec::SmallVec; + +use rustc_const_eval::interpret::InterpResult; +use rustc_data_structures::fx::FxHashSet; +use rustc_target::abi::Size; + +use crate::borrow_tracker::tree_borrows::{ + diagnostics::{NodeDebugInfo, TbError, TransitionError}, + unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap}, + Permission, +}; +use crate::borrow_tracker::{AccessKind, GlobalState, ProtectorKind}; +use crate::*; + +/// Data for a single *location*. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(super) struct LocationState { + /// This pointer's current permission + permission: Permission, + /// A location is initialized when it is child accessed for the first time, + /// and it then stays initialized forever. + /// Before initialization we still apply some preemptive transitions on + /// `permission` to know what to do in case it ever gets initialized, + /// but these can never cause any immediate UB. There can however be UB + /// the moment we attempt to initalize (i.e. child-access) because some + /// foreign access done between the creation and the initialization is + /// incompatible with child accesses. + initialized: bool, + /// Strongest foreign access whose effects have already been applied to + /// this node and all its children since the last child access. + /// This is `None` if the most recent access is a child access, + /// `Some(Write)` if at least one foreign write access has been applied + /// since the previous child access, and `Some(Read)` if at least one + /// foreign read and no foreign write have occurred since the last child access. + latest_foreign_access: Option<AccessKind>, +} + +impl LocationState { + /// Default initial state has never been accessed and has been subjected to no + /// foreign access. + fn new(permission: Permission) -> Self { + Self { permission, initialized: false, latest_foreign_access: None } + } + + /// Record that this location was accessed through a child pointer by + /// marking it as initialized + fn with_access(mut self) -> Self { + self.initialized = true; + self + } + + pub fn is_initialized(&self) -> bool { + self.initialized + } + + pub fn permission(&self) -> Permission { + self.permission + } +} + +/// Tree structure with both parents and children since we want to be +/// able to traverse the tree efficiently in both directions. +#[derive(Clone, Debug)] +pub struct Tree { + /// Mapping from tags to keys. The key obtained can then be used in + /// any of the `UniValMap` relative to this allocation, i.e. both the + /// `nodes` and `rperms` of the same `Tree`. + /// The parent-child relationship in `Node` is encoded in terms of these same + /// keys, so traversing the entire tree needs exactly one access to + /// `tag_mapping`. + pub(super) tag_mapping: UniKeyMap<BorTag>, + /// All nodes of this tree. + pub(super) nodes: UniValMap<Node>, + /// Maps a tag and a location to a perm, with possible lazy + /// initialization. + /// + /// NOTE: not all tags registered in `nodes` are necessarily in all + /// ranges of `rperms`, because `rperms` is in part lazily initialized. + /// Just because `nodes.get(key)` is `Some(_)` does not mean you can safely + /// `unwrap` any `perm.get(key)`. + /// + /// We do uphold the fact that `keys(perms)` is a subset of `keys(nodes)` + pub(super) rperms: RangeMap<UniValMap<LocationState>>, + /// The index of the root node. + pub(super) root: UniIndex, +} + +/// A node in the borrow tree. Each node is uniquely identified by a tag via +/// the `nodes` map of `Tree`. +#[derive(Clone, Debug)] +pub(super) struct Node { + /// The tag of this node. + pub tag: BorTag, + /// All tags except the root have a parent tag. + pub parent: Option<UniIndex>, + /// If the pointer was reborrowed, it has children. + // FIXME: bench to compare this to FxHashSet and to other SmallVec sizes + pub children: SmallVec<[UniIndex; 4]>, + /// Either `Reserved` or `Frozen`, the permission this tag will be lazily initialized + /// to on the first access. + default_initial_perm: Permission, + /// Some extra information useful only for debugging purposes + pub debug_info: NodeDebugInfo, +} + +/// Data given to the transition function +struct NodeAppArgs<'node> { + /// Node on which the transition is currently being applied + node: &'node Node, + /// Mutable access to its permissions + perm: UniEntry<'node, LocationState>, + /// Relative position of the access + rel_pos: AccessRelatedness, +} +/// Data given to the error handler +struct ErrHandlerArgs<'node, InErr> { + /// Kind of error that occurred + error_kind: InErr, + /// Tag that triggered the error (not the tag that was accessed, + /// rather the parent tag that had insufficient permissions or the + /// non-parent tag that had a protector). + faulty_tag: &'node NodeDebugInfo, +} +/// Internal contents of `Tree` with the minimum of mutable access for +/// the purposes of the tree traversal functions: the permissions (`perms`) can be +/// updated but not the tree structure (`tag_mapping` and `nodes`) +struct TreeVisitor<'tree> { + tag_mapping: &'tree UniKeyMap<BorTag>, + nodes: &'tree UniValMap<Node>, + perms: &'tree mut UniValMap<LocationState>, +} + +/// Whether to continue exploring the children recursively or not. +enum ContinueTraversal { + Recurse, + SkipChildren, +} + +impl<'tree> TreeVisitor<'tree> { + // Applies `f_propagate` to every vertex of the tree top-down in the following order: first + // all ancestors of `start`, then `start` itself, then children of `start`, then the rest. + // This ensures that errors are triggered in the following order + // - first invalid accesses with insufficient permissions, closest to the root first, + // - then protector violations, closest to `start` first. + // + // `f_propagate` should follow the following format: for a given `Node` it updates its + // `Permission` depending on the position relative to `start` (given by an + // `AccessRelatedness`). + // It outputs whether the tree traversal for this subree should continue or not. + fn traverse_parents_this_children_others<InnErr, OutErr>( + mut self, + start: BorTag, + f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>, + err_builder: impl Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr, + ) -> Result<(), OutErr> +where { + struct TreeVisitAux<NodeApp, ErrHandler> { + f_propagate: NodeApp, + err_builder: ErrHandler, + stack: Vec<(UniIndex, AccessRelatedness)>, + } + impl<NodeApp, InnErr, OutErr, ErrHandler> TreeVisitAux<NodeApp, ErrHandler> + where + NodeApp: Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>, + ErrHandler: Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr, + { + fn pop(&mut self) -> Option<(UniIndex, AccessRelatedness)> { + self.stack.pop() + } + + /// Apply the function to the current `tag`, and push its children + /// to the stack of future tags to visit. + fn exec_and_visit( + &mut self, + this: &mut TreeVisitor<'_>, + tag: UniIndex, + exclude: Option<UniIndex>, + rel_pos: AccessRelatedness, + ) -> Result<(), OutErr> { + // 1. apply the propagation function + let node = this.nodes.get(tag).unwrap(); + let recurse = + (self.f_propagate)(NodeAppArgs { node, perm: this.perms.entry(tag), rel_pos }) + .map_err(|error_kind| { + (self.err_builder)(ErrHandlerArgs { + error_kind, + faulty_tag: &node.debug_info, + }) + })?; + // 2. add the children to the stack for future traversal + if matches!(recurse, ContinueTraversal::Recurse) { + let child_rel = rel_pos.for_child(); + for &child in node.children.iter() { + // some child might be excluded from here and handled separately + if Some(child) != exclude { + self.stack.push((child, child_rel)); + } + } + } + Ok(()) + } + } + + let start_idx = self.tag_mapping.get(&start).unwrap(); + let mut stack = TreeVisitAux { f_propagate, err_builder, stack: Vec::new() }; + { + let mut path_ascend = Vec::new(); + // First climb to the root while recording the path + let mut curr = start_idx; + while let Some(ancestor) = self.nodes.get(curr).unwrap().parent { + path_ascend.push((ancestor, curr)); + curr = ancestor; + } + // Then descend: + // - execute f_propagate on each node + // - record children in visit + while let Some((ancestor, next_in_path)) = path_ascend.pop() { + // Explore ancestors in descending order. + // `next_in_path` is excluded from the recursion because it + // will be the `ancestor` of the next iteration. + // It also needs a different `AccessRelatedness` than the other + // children of `ancestor`. + stack.exec_and_visit( + &mut self, + ancestor, + Some(next_in_path), + AccessRelatedness::StrictChildAccess, + )?; + } + }; + // All (potentially zero) ancestors have been explored, call f_propagate on start + stack.exec_and_visit(&mut self, start_idx, None, AccessRelatedness::This)?; + // up to this point we have never popped from `stack`, hence if the + // path to the root is `root = p(n) <- p(n-1)... <- p(1) <- p(0) = start` + // then now `stack` contains + // `[<children(p(n)) except p(n-1)> ... <children(p(1)) except p(0)> <children(p(0))>]`, + // all of which are for now unexplored. + // This is the starting point of a standard DFS which will thus + // explore all non-ancestors of `start` in the following order: + // - all descendants of `start`; + // - then the unexplored descendants of `parent(start)`; + // ... + // - until finally the unexplored descendants of `root`. + while let Some((tag, rel_pos)) = stack.pop() { + stack.exec_and_visit(&mut self, tag, None, rel_pos)?; + } + Ok(()) + } +} + +impl Tree { + /// Create a new tree, with only a root pointer. + pub fn new(root_tag: BorTag, size: Size) -> Self { + let root_perm = Permission::new_root(); + let mut tag_mapping = UniKeyMap::default(); + let root_idx = tag_mapping.insert(root_tag); + let nodes = { + let mut nodes = UniValMap::<Node>::default(); + nodes.insert( + root_idx, + Node { + tag: root_tag, + parent: None, + children: SmallVec::default(), + default_initial_perm: root_perm, + debug_info: NodeDebugInfo::new(root_tag), + }, + ); + nodes + }; + let rperms = { + let mut perms = UniValMap::default(); + perms.insert(root_idx, LocationState::new(root_perm).with_access()); + RangeMap::new(size, perms) + }; + Self { root: root_idx, nodes, rperms, tag_mapping } + } +} + +impl<'tcx> Tree { + /// Insert a new tag in the tree + pub fn new_child( + &mut self, + parent_tag: BorTag, + new_tag: BorTag, + default_initial_perm: Permission, + range: AllocRange, + ) -> InterpResult<'tcx> { + assert!(!self.tag_mapping.contains_key(&new_tag)); + let idx = self.tag_mapping.insert(new_tag); + let parent_idx = self.tag_mapping.get(&parent_tag).unwrap(); + // Create the node + self.nodes.insert( + idx, + Node { + tag: new_tag, + parent: Some(parent_idx), + children: SmallVec::default(), + default_initial_perm, + debug_info: NodeDebugInfo::new(new_tag), + }, + ); + // Register new_tag as a child of parent_tag + self.nodes.get_mut(parent_idx).unwrap().children.push(idx); + // Initialize perms + let perm = LocationState::new(default_initial_perm).with_access(); + for (_range, perms) in self.rperms.iter_mut(range.start, range.size) { + perms.insert(idx, perm); + } + Ok(()) + } + + /// Deallocation requires + /// - a pointer that permits write accesses + /// - the absence of Strong Protectors anywhere in the allocation + pub fn dealloc( + &mut self, + tag: BorTag, + range: AllocRange, + global: &GlobalState, + ) -> InterpResult<'tcx> { + self.perform_access(AccessKind::Write, tag, range, global)?; + let access_info = &self.nodes.get(self.tag_mapping.get(&tag).unwrap()).unwrap().debug_info; + for (_range, perms) in self.rperms.iter_mut(range.start, range.size) { + TreeVisitor { nodes: &self.nodes, tag_mapping: &self.tag_mapping, perms } + .traverse_parents_this_children_others( + tag, + |args: NodeAppArgs<'_>| -> Result<ContinueTraversal, TransitionError> { + let NodeAppArgs { node, .. } = args; + if global.borrow().protected_tags.get(&node.tag) + == Some(&ProtectorKind::StrongProtector) + { + Err(TransitionError::ProtectedDealloc) + } else { + Ok(ContinueTraversal::Recurse) + } + }, + |args: ErrHandlerArgs<'_, TransitionError>| -> InterpErrorInfo<'tcx> { + let ErrHandlerArgs { error_kind, faulty_tag } = args; + TbError { + faulty_tag, + access_kind: AccessKind::Write, + error_kind, + tag_of_access: access_info, + } + .build() + }, + )?; + } + Ok(()) + } + + /// Maps the following propagation procedure to each range: + /// - initialize if needed; + /// - compute new state after transition; + /// - check that there is no protector that would forbid this; + /// - record this specific location as accessed. + pub fn perform_access( + &mut self, + access_kind: AccessKind, + tag: BorTag, + range: AllocRange, + global: &GlobalState, + ) -> InterpResult<'tcx> { + let access_info = &self.nodes.get(self.tag_mapping.get(&tag).unwrap()).unwrap().debug_info; + for (_range, perms) in self.rperms.iter_mut(range.start, range.size) { + TreeVisitor { nodes: &self.nodes, tag_mapping: &self.tag_mapping, perms } + .traverse_parents_this_children_others( + tag, + |args: NodeAppArgs<'_>| -> Result<ContinueTraversal, TransitionError> { + let NodeAppArgs { node, mut perm, rel_pos } = args; + + let old_state = + perm.or_insert_with(|| LocationState::new(node.default_initial_perm)); + + // Optimize the tree traversal. + // The optimization here consists of observing thanks to the tests + // `foreign_read_is_noop_after_write` and `all_transitions_idempotent` + // that if we apply twice in a row the effects of a foreign access + // we can skip some branches. + // "two foreign accesses in a row" occurs when `perm.latest_foreign_access` is `Some(_)` + // AND the `rel_pos` of the current access corresponds to a foreign access. + if rel_pos.is_foreign() { + let new_access_noop = + match (old_state.latest_foreign_access, access_kind) { + // Previously applied transition makes the new one a guaranteed + // noop in the two following cases: + // (1) justified by `foreign_read_is_noop_after_write` + (Some(AccessKind::Write), AccessKind::Read) => true, + // (2) justified by `all_transitions_idempotent` + (Some(old), new) if old == new => true, + // In all other cases there has been a recent enough + // child access that the effects of the new foreign access + // need to be applied to this subtree. + _ => false, + }; + if new_access_noop { + // Abort traversal if the new transition is indeed guaranteed + // to be noop. + return Ok(ContinueTraversal::SkipChildren); + } else { + // Otherwise propagate this time, and also record the + // access that just occurred so that we can skip the propagation + // next time. + old_state.latest_foreign_access = Some(access_kind); + } + } else { + // A child access occurred, this breaks the streak of "two foreign + // accesses in a row" and we reset this field. + old_state.latest_foreign_access = None; + } + + let old_perm = old_state.permission; + let protected = global.borrow().protected_tags.contains_key(&node.tag); + let new_perm = + Permission::perform_access(access_kind, rel_pos, old_perm, protected) + .ok_or(TransitionError::ChildAccessForbidden(old_perm))?; + if protected + // Can't trigger Protector on uninitialized locations + && old_state.initialized + && !old_perm.protector_allows_transition(new_perm) + { + return Err(TransitionError::ProtectedTransition(old_perm, new_perm)); + } + old_state.permission = new_perm; + old_state.initialized |= !rel_pos.is_foreign(); + Ok(ContinueTraversal::Recurse) + }, + |args: ErrHandlerArgs<'_, TransitionError>| -> InterpErrorInfo<'tcx> { + let ErrHandlerArgs { error_kind, faulty_tag } = args; + TbError { faulty_tag, access_kind, error_kind, tag_of_access: access_info } + .build() + }, + )?; + } + Ok(()) + } +} + +/// Integration with the BorTag garbage collector +impl Tree { + pub fn remove_unreachable_tags(&mut self, live_tags: &FxHashSet<BorTag>) { + assert!(self.keep_only_needed(self.root, live_tags)); // root can't be removed + } + + /// Traverses the entire tree looking for useless tags. + /// Returns true iff the tag it was called on is still live or has live children, + /// and removes from the tree all tags that have no live children. + /// + /// NOTE: This leaves in the middle of the tree tags that are unreachable but have + /// reachable children. There is a potential for compacting the tree by reassigning + /// children of dead tags to the nearest live parent, but it must be done with care + /// not to remove UB. + /// + /// Example: Consider the tree `root - parent - child`, with `parent: Frozen` and + /// `child: Reserved`. This tree can exist. If we blindly delete `parent` and reassign + /// `child` to be a direct child of `root` then Writes to `child` are now permitted + /// whereas they were not when `parent` was still there. + fn keep_only_needed(&mut self, idx: UniIndex, live: &FxHashSet<BorTag>) -> bool { + let node = self.nodes.get(idx).unwrap(); + // FIXME: this function does a lot of cloning, a 2-pass approach is possibly + // more efficient. It could consist of + // 1. traverse the Tree, collect all useless tags in a Vec + // 2. traverse the Vec, remove all tags previously selected + // Bench it. + let children: SmallVec<_> = node + .children + .clone() + .into_iter() + .filter(|child| self.keep_only_needed(*child, live)) + .collect(); + let no_children = children.is_empty(); + let node = self.nodes.get_mut(idx).unwrap(); + node.children = children; + if !live.contains(&node.tag) && no_children { + // All of the children and this node are unreachable, delete this tag + // from the tree (the children have already been deleted by recursive + // calls). + // Due to the API of UniMap we must absolutely call + // `UniValMap::remove` for the key of this tag on *all* maps that used it + // (which are `self.nodes` and every range of `self.rperms`) + // before we can safely apply `UniValMap::forget` to truly remove + // the tag from the mapping. + let tag = node.tag; + self.nodes.remove(idx); + for perms in self.rperms.iter_mut_all() { + perms.remove(idx); + } + self.tag_mapping.remove(&tag); + // The tag has been deleted, inform the caller + false + } else { + // The tag is still live or has live children, it must be kept + true + } + } +} + +impl VisitTags for Tree { + fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { + // To ensure that the root never gets removed, we visit it + // (the `root` node of `Tree` is not an `Option<_>`) + visit(self.nodes.get(self.root).unwrap().tag) + } +} + +/// Relative position of the access +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum AccessRelatedness { + /// The accessed pointer is the current one + This, + /// The accessed pointer is a (transitive) child of the current one. + // Current pointer is excluded (unlike in some other places of this module + // where "child" is inclusive). + StrictChildAccess, + /// The accessed pointer is a (transitive) parent of the current one. + // Current pointer is excluded. + AncestorAccess, + /// The accessed pointer is neither of the above. + // It's a cousin/uncle/etc., something in a side branch. + // FIXME: find a better name ? + DistantAccess, +} + +impl AccessRelatedness { + /// Check that access is either Ancestor or Distant, i.e. not + /// a transitive child (initial pointer included). + pub fn is_foreign(self) -> bool { + matches!(self, AccessRelatedness::AncestorAccess | AccessRelatedness::DistantAccess) + } + + /// Given the AccessRelatedness for the parent node, compute the AccessRelatedness + /// for the child node. This function assumes that we propagate away from the initial + /// access. + pub fn for_child(self) -> Self { + use AccessRelatedness::*; + match self { + AncestorAccess | This => AncestorAccess, + StrictChildAccess | DistantAccess => DistantAccess, + } + } +} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs new file mode 100644 index 00000000000..c1d452ca89e --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs @@ -0,0 +1,304 @@ +//! This module implements the `UniMap`, which is a way to get efficient mappings +//! optimized for the setting of `tree_borrows/tree.rs`. +//! +//! A `UniKeyMap<K>` is a (slow) mapping from `K` to `UniIndex`, +//! and `UniValMap<V>` is a (fast) mapping from `UniIndex` to `V`. +//! Thus a pair `(UniKeyMap<K>, UniValMap<V>)` acts as a virtual `HashMap<K, V>`. +//! +//! Because of the asymmetry in access time, the use-case for `UniMap` is the following: +//! a tuple `(UniKeyMap<K>, Vec<UniValMap<V>>)` is much more efficient than +//! the equivalent `Vec<HashMap<K, V>>` it represents if all maps have similar +//! sets of keys. + +#![allow(dead_code)] + +use std::hash::Hash; + +use rustc_data_structures::fx::FxHashMap; + +/// Intermediate key between a UniKeyMap and a UniValMap. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UniIndex { + idx: u32, +} + +/// From K to UniIndex +#[derive(Debug, Clone, Default)] +pub struct UniKeyMap<K> { + /// Underlying map that does all the hard work. + /// Key invariant: the contents of `deassigned` are disjoint from the + /// keys of `mapping`, and together they form the set of contiguous integers + /// `0 .. (mapping.len() + deassigned.len())`. + mapping: FxHashMap<K, u32>, + /// Indexes that can be reused: memory gain when the map gets sparse + /// due to many deletions. + deassigned: Vec<u32>, +} + +/// From UniIndex to V +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct UniValMap<V> { + /// The mapping data. Thanks to Vec we get both fast accesses, and + /// a memory-optimal representation if there are few deletions. + data: Vec<Option<V>>, +} + +impl<V> Default for UniValMap<V> { + fn default() -> Self { + Self { data: Vec::default() } + } +} + +impl<K> UniKeyMap<K> +where + K: Hash + Eq, +{ + /// How many keys/index pairs are currently active. + pub fn len(&self) -> usize { + self.mapping.len() + } + + /// Whether this key has an associated index or not. + pub fn contains_key(&self, key: &K) -> bool { + self.mapping.contains_key(key) + } + + /// Assign this key to a new index. Panics if the key is already assigned, + /// use `get_or_insert` for a version that instead returns the existing + /// assignment. + #[track_caller] + pub fn insert(&mut self, key: K) -> UniIndex { + // We want an unused index. First we attempt to find one from `deassigned`, + // and if `deassigned` is empty we generate a fresh index. + let idx = self.deassigned.pop().unwrap_or_else(|| { + // `deassigned` is empty, so all keys in use are already in `mapping`. + // The next available key is `mapping.len()`. + self.mapping.len().try_into().expect("UniMap ran out of useable keys") + }); + if self.mapping.insert(key, idx).is_some() { + panic!( + "This key is already assigned to a different index; either use `get_or_insert` instead if you care about this data, or first call `remove` to undo the preexisting assignment." + ); + }; + UniIndex { idx } + } + + /// If it exists, the index this key maps to. + pub fn get(&self, key: &K) -> Option<UniIndex> { + self.mapping.get(key).map(|&idx| UniIndex { idx }) + } + + /// Either get a previously existing entry, or create a new one if it + /// is not yet present. + pub fn get_or_insert(&mut self, key: K) -> UniIndex { + self.get(&key).unwrap_or_else(|| self.insert(key)) + } + + /// Return whatever index this key was using to the deassigned pool. + /// + /// Note: calling this function can be dangerous. If the index still exists + /// somewhere in a `UniValMap` and is reassigned by the `UniKeyMap` then + /// it will inherit the old value of a completely unrelated key. + /// If you `UniKeyMap::remove` a key you should make sure to also `UniValMap::remove` + /// the associated `UniIndex` from ALL `UniValMap`s. + /// + /// Example of such behavior: + /// ``` + /// let mut keymap = UniKeyMap::<char>::default(); + /// let mut valmap = UniValMap::<char>::default(); + /// // Insert 'a' -> _ -> 'A' + /// let idx_a = keymap.insert('a'); + /// valmap.insert(idx_a, 'A'); + /// // Remove 'a' -> _, but forget to remove _ -> 'A' + /// keymap.remove(&'a'); + /// // valmap.remove(idx_a); // If we uncomment this line the issue is fixed + /// // Insert 'b' -> _ + /// let idx_b = keymap.insert('b'); + /// let val_b = valmap.get(idx_b); + /// assert_eq!(val_b, Some('A')); // Oh no + /// // assert_eq!(val_b, None); // This is what we would have expected + /// ``` + pub fn remove(&mut self, key: &K) { + if let Some(idx) = self.mapping.remove(key) { + self.deassigned.push(idx); + } + } +} + +impl<V> UniValMap<V> { + /// Whether this index has an associated value. + pub fn contains_idx(&self, idx: UniIndex) -> bool { + self.data.get(idx.idx as usize).and_then(Option::as_ref).is_some() + } + + /// Reserve enough space to insert the value at the right index. + fn extend_to_length(&mut self, len: usize) { + if len > self.data.len() { + let nb = len - self.data.len(); + self.data.reserve(nb); + for _ in 0..nb { + self.data.push(None); + } + } + } + + /// Assign a value to the index. Permanently overwrites any previous value. + pub fn insert(&mut self, idx: UniIndex, val: V) { + self.extend_to_length(idx.idx as usize + 1); + self.data[idx.idx as usize] = Some(val) + } + + /// Get the value at this index, if it exists. + pub fn get(&self, idx: UniIndex) -> Option<&V> { + self.data.get(idx.idx as usize).and_then(Option::as_ref) + } + + /// Get the value at this index mutably, if it exists. + pub fn get_mut(&mut self, idx: UniIndex) -> Option<&mut V> { + self.data.get_mut(idx.idx as usize).and_then(Option::as_mut) + } + + /// Delete any value associated with this index. Ok even if the index + /// has no associated value. + pub fn remove(&mut self, idx: UniIndex) { + if idx.idx as usize >= self.data.len() { + return; + } + self.data[idx.idx as usize] = None; + } +} + +/// An access to a single value of the map. +pub struct UniEntry<'a, V> { + inner: &'a mut Option<V>, +} + +impl<'a, V> UniValMap<V> { + /// Get a wrapper around a mutable access to the value corresponding to `idx`. + pub fn entry(&'a mut self, idx: UniIndex) -> UniEntry<'a, V> { + self.extend_to_length(idx.idx as usize + 1); + UniEntry { inner: &mut self.data[idx.idx as usize] } + } +} + +impl<'a, V> UniEntry<'a, V> { + /// Insert in the map and get the value. + pub fn or_insert_with<F>(&mut self, default: F) -> &mut V + where + F: FnOnce() -> V, + { + if self.inner.is_none() { + *self.inner = Some(default()); + } + self.inner.as_mut().unwrap() + } +} + +mod tests { + use super::*; + + #[test] + fn extend_to_length() { + let mut km = UniValMap::<char>::default(); + km.extend_to_length(10); + assert!(km.data.len() == 10); + km.extend_to_length(0); + assert!(km.data.len() == 10); + km.extend_to_length(10); + assert!(km.data.len() == 10); + km.extend_to_length(11); + assert!(km.data.len() == 11); + } + + #[derive(Default)] + struct MapWitness<K, V> { + key: UniKeyMap<K>, + val: UniValMap<V>, + map: FxHashMap<K, V>, + } + + impl<K, V> MapWitness<K, V> + where + K: Copy + Hash + Eq, + V: Copy + Eq + std::fmt::Debug, + { + fn insert(&mut self, k: K, v: V) { + // UniMap + let i = self.key.get_or_insert(k); + self.val.insert(i, v); + // HashMap + self.map.insert(k, v); + // Consistency: nothing to check + } + + fn get(&self, k: &K) { + // UniMap + let v1 = self.key.get(k).and_then(|i| self.val.get(i)); + // HashMap + let v2 = self.map.get(k); + // Consistency + assert_eq!(v1, v2); + } + + fn get_mut(&mut self, k: &K) { + // UniMap + let v1 = self.key.get(k).and_then(|i| self.val.get_mut(i)); + // HashMap + let v2 = self.map.get_mut(k); + // Consistency + assert_eq!(v1, v2); + } + fn remove(&mut self, k: &K) { + // UniMap + if let Some(i) = self.key.get(k) { + self.val.remove(i); + } + self.key.remove(k); + // HashMap + self.map.remove(k); + // Consistency: nothing to check + } + } + + #[test] + fn consistency_small() { + let mut m = MapWitness::<u64, char>::default(); + m.insert(1, 'a'); + m.insert(2, 'b'); + m.get(&1); + m.get_mut(&2); + m.remove(&2); + m.insert(1, 'c'); + m.get(&1); + m.insert(3, 'd'); + m.insert(4, 'e'); + m.insert(4, 'f'); + m.get(&2); + m.get(&3); + m.get(&4); + m.get(&5); + m.remove(&100); + m.get_mut(&100); + m.get(&100); + } + + #[test] + fn consistency_large() { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + let mut hasher = DefaultHasher::new(); + let mut map = MapWitness::<u64, u64>::default(); + for i in 0..1000 { + i.hash(&mut hasher); + let rng = hasher.finish(); + let op = rng % 3 == 0; + let key = (rng / 2) % 50; + let val = (rng / 100) % 1000; + if op { + map.insert(key, val); + } else { + map.get(&key); + } + } + } +} diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 035c0e64233..3c13118122c 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -22,6 +22,10 @@ pub enum TerminationInfo { help: Option<String>, history: Option<TagHistory>, }, + TreeBorrowsUb { + msg: String, + // FIXME: incomplete + }, Int2PtrWithStrictProvenance, Deadlock, MultipleSymbolDefinitions { @@ -61,6 +65,7 @@ impl fmt::Display for TerminationInfo { "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`" ), StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), + TreeBorrowsUb { msg } => write!(f, "{msg}"), Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{link_name}`"), @@ -184,7 +189,8 @@ pub fn report_error<'tcx, 'mir>( Abort(_) => Some("abnormal termination"), UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance => Some("unsupported operation"), - StackedBorrowsUb { .. } | DataRace { .. } => Some("Undefined Behavior"), + StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } => + Some("Undefined Behavior"), Deadlock => Some("deadlock"), MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; @@ -212,6 +218,12 @@ pub fn report_error<'tcx, 'mir>( } } helps + }, + TreeBorrowsUb { .. } => { + let helps = vec![ + (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental")), + ]; + helps } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 8443e907938..a32b18595b5 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -87,7 +87,7 @@ pub struct MiriConfig { pub env: Vec<(OsString, OsString)>, /// Determine if validity checking is enabled. pub validate: bool, - /// Determines if Stacked Borrows is enabled. + /// Determines if Stacked Borrows or Tree Borrows is enabled. pub borrow_tracker: Option<BorrowTrackerMethod>, /// Controls alignment checking. pub check_alignment: AlignmentCheck, @@ -134,7 +134,7 @@ pub struct MiriConfig { pub preemption_rate: f64, /// Report the current instruction being executed every N basic blocks. pub report_progress: Option<u32>, - /// Whether Stacked Borrows retagging should recurse into fields of datatypes. + /// Whether Stacked Borrows and Tree Borrows retagging should recurse into fields of datatypes. pub retag_fields: RetagFields, /// The location of a shared object file to load when calling external functions /// FIXME! consider allowing users to specify paths to multiple SO files, or to a directory diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index ed3dd741a8b..21a413002d0 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1,5 +1,6 @@ pub mod convert; +use std::any::Any; use std::cmp; use std::iter; use std::num::NonZeroUsize; @@ -23,7 +24,23 @@ use rand::RngCore; use crate::*; -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +/// A trait to work around not having trait object upcasting: +/// Add `AsAny` as supertrait and your trait objects can be turned into `&dyn Any` on which you can +/// then call `downcast`. +pub trait AsAny: Any { + fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; +} +impl<T: Any> AsAny for T { + #[inline(always)] + fn as_any(&self) -> &dyn Any { + self + } + #[inline(always)] + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} // This mapping should match `decode_error_kind` in // <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/mod.rs>. @@ -119,6 +136,7 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>) } } +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Checks if the given crate/module exists. fn have_module(&self, path: &[&str]) -> bool { diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index f64f216520f..01d0f01d319 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -9,6 +9,7 @@ #![feature(nonzero_ops)] #![feature(local_key_cell_methods)] #![feature(is_terminal)] +#![feature(round_ties_even)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -94,6 +95,7 @@ pub use crate::shims::EvalContextExt as _; pub use crate::borrow_tracker::stacked_borrows::{ EvalContextExt as _, Item, Permission, Stack, Stacks, }; +pub use crate::borrow_tracker::tree_borrows::{EvalContextExt as _, Tree}; pub use crate::borrow_tracker::{ BorTag, BorrowTrackerMethod, CallId, EvalContextExt as _, RetagFields, }; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 969c81f7e32..cc1964de332 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -38,7 +38,7 @@ pub const SIGRTMAX: i32 = 42; /// Extra data stored with each stack frame pub struct FrameExtra<'tcx> { - /// Extra data for Stacked Borrows. + /// Extra data for the Borrow Tracker. pub borrow_tracker: Option<borrow_tracker::FrameState>, /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn` @@ -146,7 +146,7 @@ impl fmt::Display for MiriMemoryKind { pub enum Provenance { Concrete { alloc_id: AllocId, - /// Stacked Borrows tag. + /// Borrow Tracker tag. tag: BorTag, }, Wildcard, @@ -195,7 +195,7 @@ impl fmt::Debug for Provenance { } else { write!(f, "[{alloc_id:?}]")?; } - // Print Stacked Borrows tag. + // Print Borrow Tracker tag. write!(f, "{tag:?}")?; } Provenance::Wildcard => { @@ -812,7 +812,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { } #[inline(always)] - fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool { + fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>, _layout: TyAndLayout<'tcx>) -> bool { ecx.machine.validate } @@ -822,7 +822,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { } #[inline(always)] - fn ignore_checkable_overflow_assertions(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool { + fn ignore_optional_overflow_checks(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool { !ecx.tcx.sess.overflow_checks() } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 03275ed4ed1..73439133af2 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -232,6 +232,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } + /// Read bytes from a `(ptr, len)` argument + fn read_byte_slice<'i>(&'i self, bytes: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, &'i [u8]> + where + 'mir: 'i, + { + let this = self.eval_context_ref(); + let (ptr, len) = this.read_immediate(bytes)?.to_scalar_pair(); + let ptr = ptr.to_pointer(this)?; + let len = len.to_target_usize(this)?; + let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; + Ok(bytes) + } + /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. /// Returns Ok(None) if the foreign item was completely handled @@ -427,13 +440,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { })?; this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?; } - "miri_print_borrow_stacks" => { - let [id] = this.check_shim(abi, Abi::Rust, link_name, args)?; + "miri_print_borrow_state" => { + let [id, show_unnamed] = this.check_shim(abi, Abi::Rust, link_name, args)?; let id = this.read_scalar(id)?.to_u64()?; + let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; if let Some(id) = std::num::NonZeroU64::new(id) { - this.print_stacks(AllocId(id))?; + this.print_borrow_state(AllocId(id), show_unnamed)?; } } + "miri_pointer_name" => { + // This associates a name to a tag. Very useful for debugging, and also makes + // tests more strict. + let [ptr, nth_parent, name] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let ptr = this.read_pointer(ptr)?; + let nth_parent = this.read_scalar(nth_parent)?.to_u8()?; + let name = this.read_byte_slice(name)?; + // We must make `name` owned because we need to + // end the shared borrow from `read_byte_slice` before we can + // start the mutable borrow for `give_pointer_debug_name`. + let name = String::from_utf8_lossy(name).into_owned(); + this.give_pointer_debug_name(ptr, nth_parent, &name)?; + } "miri_static_root" => { let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; @@ -487,12 +514,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Writes some bytes to the interpreter's stdout/stderr. See the // README for details. "miri_write_to_stdout" | "miri_write_to_stderr" => { - let [bytes] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let (ptr, len) = this.read_immediate(bytes)?.to_scalar_pair(); - let ptr = ptr.to_pointer(this)?; - let len = len.to_target_usize(this)?; - let msg = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; - + let [msg] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let msg = this.read_byte_slice(msg)?; // Note: we're ignoring errors writing to host stdout/stderr. let _ignore = match link_name.as_str() { "miri_write_to_stdout" => std::io::stdout().write_all(msg), diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index d21a1560699..9ecbb18ef5a 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -157,6 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "ceilf32" | "truncf32" | "roundf32" + | "rintf32" => { let [f] = check_arg_count(args)?; // FIXME: Using host floats. @@ -174,6 +175,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "ceilf32" => f.ceil(), "truncf32" => f.trunc(), "roundf32" => f.round(), + "rintf32" => f.round_ties_even(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; @@ -192,6 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "ceilf64" | "truncf64" | "roundf64" + | "rintf64" => { let [f] = check_arg_count(args)?; // FIXME: Using host floats. @@ -209,6 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "ceilf64" => f.ceil(), "truncf64" => f.trunc(), "roundf64" => f.round(), + "rintf64" => f.round_ties_even(), _ => bug!(), }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index d05c4d98fad..1eca389e984 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -17,7 +17,6 @@ use crate::shims::os_str::bytes_to_os_str; use crate::*; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; -use shims::unix::linux::fd::epoll::Epoll; #[derive(Debug)] pub struct FileHandle { @@ -25,17 +24,9 @@ pub struct FileHandle { writable: bool, } -pub trait FileDescriptor: std::fmt::Debug { +pub trait FileDescriptor: std::fmt::Debug + helpers::AsAny { fn name(&self) -> &'static str; - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("{} cannot be used as FileHandle", self.name()); - } - - fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> { - throw_unsup_format!("not an epoll file descriptor"); - } - fn read<'tcx>( &mut self, _communicate_allowed: bool, @@ -69,7 +60,9 @@ pub trait FileDescriptor: std::fmt::Debug { fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>>; - fn is_tty(&self) -> bool; + fn is_tty(&self) -> bool { + false + } #[cfg(unix)] fn as_unix_host_fd(&self) -> Option<i32> { @@ -82,10 +75,6 @@ impl FileDescriptor for FileHandle { "FILE" } - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - Ok(self) - } - fn read<'tcx>( &mut self, communicate_allowed: bool, @@ -271,10 +260,6 @@ impl FileDescriptor for NullOutput { fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { Ok(Box::new(NullOutput)) } - - fn is_tty(&self) -> bool { - false - } } #[derive(Debug)] @@ -694,7 +679,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`F_FULLFSYNC` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { @@ -1530,7 +1520,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_i32( if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`ftruncate64` is only supported on file-backed file descriptors" + ) + })?; if *writable { if let Ok(length) = length.try_into() { let result = file.set_len(length); @@ -1571,7 +1566,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fsync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!("`fsync` is only supported on file-backed file descriptors") + })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { @@ -1593,7 +1591,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fdatasync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`fdatasync` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) } else { @@ -1638,7 +1641,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`sync_data_range` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } else { @@ -1942,7 +1950,16 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option<FileMetadata>> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(file_descriptor) => &file_descriptor.as_file_handle()?.file, + Some(file_descriptor) => + &file_descriptor + .as_any() + .downcast_ref::<FileHandle>() + .ok_or_else(|| { + err_unsup_format!( + "obtaining metadata is only supported on file-backed file descriptors" + ) + })? + .file, None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs index fd4927fa10c..3c4a678e598 100644 --- a/src/tools/miri/src/shims/unix/linux/fd.rs +++ b/src/tools/miri/src/shims/unix/linux/fd.rs @@ -80,7 +80,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let event = EpollEvent { events, data }; if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let epfd = epfd.as_epoll_handle()?; + let epfd = epfd + .as_any_mut() + .downcast_mut::<Epoll>() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; epfd.file_descriptors.insert(fd, event); Ok(Scalar::from_i32(0)) @@ -89,7 +92,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } else if op == epoll_ctl_del { if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let epfd = epfd.as_epoll_handle()?; + let epfd = epfd + .as_any_mut() + .downcast_mut::<Epoll>() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; epfd.file_descriptors.remove(&fd); Ok(Scalar::from_i32(0)) @@ -148,7 +154,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let numevents = 0; if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let _epfd = epfd.as_epoll_handle()?; + let _epfd = epfd + .as_any_mut() + .downcast_mut::<Epoll>() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; // FIXME return number of events ready when scheme for marking events ready exists Ok(Scalar::from_i32(numevents)) diff --git a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs index e33673fecf6..a429caaf8f4 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs @@ -32,18 +32,10 @@ impl FileDescriptor for Epoll { "epoll" } - fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> { - Ok(self) - } - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { Ok(Box::new(self.clone())) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box<Self>, _communicate_allowed: bool, diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs index b28a6e0c56e..1db020bb7b6 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/event.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs @@ -28,10 +28,6 @@ impl FileDescriptor for Event { Ok(Box::new(Event { val: self.val.clone() })) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box<Self>, _communicate_allowed: bool, diff --git a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs index f9e56b4a2b4..6adae88235f 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs @@ -19,10 +19,6 @@ impl FileDescriptor for SocketPair { Ok(Box::new(SocketPair)) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box<Self>, _communicate_allowed: bool, diff --git a/src/tools/miri/src/shims/windows/dlsym.rs b/src/tools/miri/src/shims/windows/dlsym.rs index 60dd299c438..7e2051fc98a 100644 --- a/src/tools/miri/src/shims/windows/dlsym.rs +++ b/src/tools/miri/src/shims/windows/dlsym.rs @@ -1,5 +1,4 @@ use rustc_middle::mir; -use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use log::trace; @@ -11,7 +10,6 @@ use crate::*; #[derive(Debug, Copy, Clone)] pub enum Dlsym { - NtWriteFile, SetThreadDescription, WaitOnAddress, WakeByAddressSingle, @@ -23,7 +21,6 @@ impl Dlsym { pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, - "NtWriteFile" => Some(Dlsym::NtWriteFile), "SetThreadDescription" => Some(Dlsym::SetThreadDescription), "WaitOnAddress" => Some(Dlsym::WaitOnAddress), "WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle), @@ -49,72 +46,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.check_abi(abi, Abi::System { unwind: false })?; match dlsym { - Dlsym::NtWriteFile => { - if !this.frame_in_std() { - throw_unsup_format!( - "`NtWriteFile` support is crude and just enough for stdout to work" - ); - } - - let [ - handle, - _event, - _apc_routine, - _apc_context, - io_status_block, - buf, - n, - byte_offset, - _key, - ] = check_arg_count(args)?; - let handle = this.read_target_isize(handle)?; - let buf = this.read_pointer(buf)?; - let n = this.read_scalar(n)?.to_u32()?; - let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer - let io_status_block = this.deref_operand(io_status_block)?; - - if byte_offset != 0 { - throw_unsup_format!( - "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported" - ); - } - - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = - this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; - let res = if this.machine.mute_stdout_stderr { - Ok(buf_cont.len()) - } else if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. - res.ok().map(|n| u32::try_from(n).unwrap()) - } else { - throw_unsup_format!( - "on Windows, writing to anything except stdout/stderr is not supported" - ) - }; - // We have to put the result into io_status_block. - if let Some(n) = written { - let io_status_information = - this.mplace_field_named(&io_status_block, "Information")?; - this.write_scalar( - Scalar::from_target_usize(n.into(), this), - &io_status_information.into(), - )?; - } - // Return whether this was a success. >= 0 is success. - // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. - this.write_scalar( - Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), - dest, - )?; - } Dlsym::SetThreadDescription => { let [handle, name] = check_arg_count(args)?; diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index a3d7176a976..665c7ed438f 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -69,6 +69,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(result, dest)?; } + // File related shims + "NtWriteFile" => { + if !this.frame_in_std() { + throw_unsup_format!( + "`NtWriteFile` support is crude and just enough for stdout to work" + ); + } + + let [ + handle, + _event, + _apc_routine, + _apc_context, + io_status_block, + buf, + n, + byte_offset, + _key, + ] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let handle = this.read_target_isize(handle)?; + let buf = this.read_pointer(buf)?; + let n = this.read_scalar(n)?.to_u32()?; + let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer + let io_status_block = this.deref_operand(io_status_block)?; + + if byte_offset != 0 { + throw_unsup_format!( + "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported" + ); + } + + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = + this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; + let res = if this.machine.mute_stdout_stderr { + Ok(buf_cont.len()) + } else if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. + res.ok().map(|n| u32::try_from(n).unwrap()) + } else { + throw_unsup_format!( + "on Windows, writing to anything except stdout/stderr is not supported" + ) + }; + // We have to put the result into io_status_block. + if let Some(n) = written { + let io_status_information = + this.mplace_field_named(&io_status_block, "Information")?; + this.write_scalar( + Scalar::from_target_usize(n.into(), this), + &io_status_information.into(), + )?; + } + // Return whether this was a success. >= 0 is success. + // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. + this.write_scalar( + Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), + dest, + )?; + } + // Allocation "HeapAlloc" => { let [handle, flags, size] = diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index 1d7ed34c59a..21eaeabe6ad 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -139,8 +139,9 @@ regexes! { STDOUT: // Windows file paths r"\\" => "/", - // erase Stacked Borrows tags + // erase borrow tags "<[0-9]+>" => "<TAG>", + "<[0-9]+=" => "<TAG=", } regexes! { @@ -149,8 +150,9 @@ regexes! { r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC", // erase alloc ids "alloc[0-9]+" => "ALLOC", - // erase Stacked Borrows tags + // erase borrow tags "<[0-9]+>" => "<TAG>", + "<[0-9]+=" => "<TAG=", // erase whitespace that differs between platforms r" +at (.*\.rs)" => " at $1", // erase generics in backtraces diff --git a/src/tools/miri/tests/fail/never_transmute_humans.rs b/src/tools/miri/tests/fail/never_transmute_humans.rs index de723433dc2..cba3cc0ccf1 100644 --- a/src/tools/miri/tests/fail/never_transmute_humans.rs +++ b/src/tools/miri/tests/fail/never_transmute_humans.rs @@ -7,6 +7,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::<Human, !>(Human) //~ ERROR: transmuting to uninhabited + std::mem::transmute::<Human, !>(Human) //~ ERROR: entering unreachable code }; } diff --git a/src/tools/miri/tests/fail/never_transmute_humans.stderr b/src/tools/miri/tests/fail/never_transmute_humans.stderr index e8df4739f9b..a51ca7fe7e7 100644 --- a/src/tools/miri/tests/fail/never_transmute_humans.stderr +++ b/src/tools/miri/tests/fail/never_transmute_humans.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: transmuting to uninhabited type +error: Undefined Behavior: entering unreachable code --> $DIR/never_transmute_humans.rs:LL:CC | LL | std::mem::transmute::<Human, !>(Human) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/never_transmute_void.rs b/src/tools/miri/tests/fail/never_transmute_void.rs index 19473e9ac21..ad67b444616 100644 --- a/src/tools/miri/tests/fail/never_transmute_void.rs +++ b/src/tools/miri/tests/fail/never_transmute_void.rs @@ -10,11 +10,13 @@ mod m { pub struct Void(VoidI); pub fn f(v: Void) -> ! { - match v.0 {} //~ ERROR: entering unreachable code + match v.0 {} + //~^ ERROR: entering unreachable code } } fn main() { let v = unsafe { std::mem::transmute::<(), m::Void>(()) }; - m::f(v); //~ NOTE: inside `main` + m::f(v); + //~^ NOTE: inside `main` } diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs index a63cd03366f..0637e08af9b 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs @@ -1,4 +1,4 @@ -//! Make sure that a retag acts like a write for the data race model. +//! Make sure that a retag acts like a read for the data race model. //@compile-flags: -Zmiri-preemption-rate=0 #[derive(Copy, Clone)] struct SendPtr(*mut u8); diff --git a/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs new file mode 100644 index 00000000000..122a8ff8752 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs @@ -0,0 +1,19 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Check that TB properly rejects alternating Reads and Writes, but tolerates +// alternating only Reads to Reserved mutable references. +pub fn main() { + let x = &mut 0u8; + let y = unsafe { &mut *(x as *mut u8) }; + // Foreign Read, but this is a no-op from the point of view of y (still Reserved) + let _val = *x; + // Now we activate y, for this to succeed y needs to not have been Frozen + // by the previous operation + *y += 1; // Success + // This time y gets Frozen... + let _val = *x; + // ... and the next Write attempt fails. + *y += 1; // Failure //~ ERROR: /write access through .* is forbidden/ + let _val = *x; + *y += 1; // Unreachable +} diff --git a/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr new file mode 100644 index 00000000000..7c5bcd4e7b0 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr @@ -0,0 +1,14 @@ +error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + --> $DIR/alternate-read-write.rs:LL:CC + | +LL | *y += 1; // Failure + | ^^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main` at $DIR/alternate-read-write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs new file mode 100644 index 00000000000..215100de0a1 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs @@ -0,0 +1,42 @@ +//! Race-condition-like interaction between a read and a reborrow. +//! Even though no write or fake write occurs, reads have an effect on protected +//! Reserved. This is a protected-retag/read data race, but is not *detected* as +//! a data race violation because reborrows are not writes. +//! +//! This test is sensitive to the exact schedule so we disable preemption. +//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0 +use std::ptr::addr_of_mut; +use std::thread; + +#[derive(Copy, Clone)] +struct SendPtr(*mut u8); + +unsafe impl Send for SendPtr {} + +// First thread is just a reborrow, but for an instant `x` is +// protected and thus vulnerable to foreign reads. +fn thread_1(x: &mut u8) -> SendPtr { + thread::yield_now(); // make the other thread go first + SendPtr(x as *mut u8) +} + +// Second thread simply performs a read. +fn thread_2(x: &u8) { + let _val = *x; +} + +fn main() { + let mut x = 0u8; + let x_1 = unsafe { &mut *addr_of_mut!(x) }; + let xg = unsafe { &*addr_of_mut!(x) }; + + // The two threads are executed in parallel on aliasing pointers. + // UB occurs if the read of thread_2 occurs while the protector of thread_1 + // is in place. + let hf = thread::spawn(move || thread_1(x_1)); + let hg = thread::spawn(move || thread_2(xg)); + let SendPtr(p) = hf.join().unwrap(); + let () = hg.join().unwrap(); + + unsafe { *p = 1 }; //~ ERROR: /write access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr new file mode 100644 index 00000000000..a078d18d3b0 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr @@ -0,0 +1,14 @@ +error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + --> $DIR/fragile-data-race.rs:LL:CC + | +LL | unsafe { *p = 1 }; + | ^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main` at $DIR/fragile-data-race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/outside-range.rs b/src/tools/miri/tests/fail/tree-borrows/outside-range.rs new file mode 100644 index 00000000000..8450e1c168d --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/outside-range.rs @@ -0,0 +1,22 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Check that in the case of locations outside the range of a pointer, +// protectors trigger if and only if the location has already been accessed +fn main() { + unsafe { + let data = &mut [0u8, 1, 2, 3]; + let raw = data.as_mut_ptr(); + stuff(&mut *raw, raw); + } +} + +unsafe fn stuff(x: &mut u8, y: *mut u8) { + let xraw = x as *mut u8; + // No issue here: location 1 is not accessed + *y.add(1) = 42; + // Still no issue: location 2 is not invalidated + let _val = *xraw.add(2); + // However protector triggers if location is both accessed and invalidated + let _val = *xraw.add(3); + *y.add(3) = 42; //~ ERROR: /write access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr b/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr new file mode 100644 index 00000000000..4396c63679e --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: write access through <TAG> is forbidden because it is a foreign tag for <TAG>, which would hence change from Reserved to Disabled, but <TAG> is protected + --> $DIR/outside-range.rs:LL:CC + | +LL | *y.add(3) = 42; + | ^^^^^^^^^^^^^^ write access through <TAG> is forbidden because it is a foreign tag for <TAG>, which would hence change from Reserved to Disabled, but <TAG> is protected + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `stuff` at $DIR/outside-range.rs:LL:CC +note: inside `main` + --> $DIR/outside-range.rs:LL:CC + | +LL | stuff(&mut *raw, raw); + | ^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs b/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs new file mode 100644 index 00000000000..025b7ad22dc --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs @@ -0,0 +1,14 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Read to local variable kills reborrows *and* raw pointers derived from them. +// This test would succeed under Stacked Borrows. +fn main() { + unsafe { + let mut root = 6u8; + let mref = &mut root; + let ptr = mref as *mut u8; + *ptr = 0; // Write + assert_eq!(root, 0); // Parent Read + *ptr = 0; //~ ERROR: /write access through .* is forbidden/ + } +} diff --git a/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr b/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr new file mode 100644 index 00000000000..7d9367c87d0 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr @@ -0,0 +1,14 @@ +error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + --> $DIR/read-to-local.rs:LL:CC + | +LL | *ptr = 0; + | ^^^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main` at $DIR/read-to-local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs new file mode 100644 index 00000000000..872efe3ad59 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs @@ -0,0 +1,34 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +// Check how a Reserved with interior mutability +// responds to a Foreign Write under a Protector +#[path = "../../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +use std::cell::UnsafeCell; + +fn main() { + unsafe { + let n = &mut UnsafeCell::new(0u8); + name!(n.get(), "base"); + let x = &mut *(n as *mut UnsafeCell<_>); + name!(x.get(), "x"); + let y = (&mut *n).get(); + name!(y); + write_second(x, y); + unsafe fn write_second(x: &mut UnsafeCell<u8>, y: *mut u8) { + let alloc_id = alloc_id!(x.get()); + name!(x.get(), "callee:x"); + name!(x.get()=>1, "caller:x"); + name!(y, "callee:y"); + name!(y, "caller:y"); + print_state!(alloc_id); + // Right before the faulty Write, x is + // - Reserved + // - with interior mut + // - Protected + *y = 1; //~ ERROR: /write access through .* is forbidden/ + } + } +} diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr new file mode 100644 index 00000000000..8ae1c09470a --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr @@ -0,0 +1,28 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Re*| └─┬──<TAG=base> +| Re*| ├─┬──<TAG=x> +| Re*| │ └─┬──<TAG=caller:x> +| Re*| │ └────<TAG=callee:x> Strongly protected +| Re*| └────<TAG=y,callee:y,caller:y> +────────────────────────────────────────────────────────────────────── +error: Undefined Behavior: write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected + --> $DIR/cell-protected-write.rs:LL:CC + | +LL | *y = 1; + | ^^^^^^ write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main::write_second` at $DIR/cell-protected-write.rs:LL:CC +note: inside `main` + --> $DIR/cell-protected-write.rs:LL:CC + | +LL | write_second(x, y); + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs new file mode 100644 index 00000000000..3a1205a84f7 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs @@ -0,0 +1,32 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +#[path = "../../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +// Check how a Reserved without interior mutability responds to a Foreign +// Write when under a protector +fn main() { + unsafe { + let n = &mut 0u8; + name!(n); + let x = &mut *(n as *mut _); + name!(x); + let y = (&mut *n) as *mut _; + name!(y); + write_second(x, y); + unsafe fn write_second(x: &mut u8, y: *mut u8) { + let alloc_id = alloc_id!(x); + name!(x, "callee:x"); + name!(x=>1, "caller:x"); + name!(y, "callee:y"); + name!(y, "caller:y"); + print_state!(alloc_id); + // Right before the faulty Write, x is + // - Reserved + // - Protected + // The Write turns it Disabled + *y = 0; //~ ERROR: /write access through .* is forbidden/ + } + } +} diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr new file mode 100644 index 00000000000..a199fc0f0da --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr @@ -0,0 +1,28 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=n> +| Res| ├─┬──<TAG=x> +| Res| │ └─┬──<TAG=caller:x> +| Res| │ └────<TAG=callee:x> Strongly protected +| Res| └────<TAG=y,callee:y,caller:y> +────────────────────────────────────────────────────────────────────── +error: Undefined Behavior: write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected + --> $DIR/int-protected-write.rs:LL:CC + | +LL | *y = 0; + | ^^^^^^ write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main::write_second` at $DIR/int-protected-write.rs:LL:CC +note: inside `main` + --> $DIR/int-protected-write.rs:LL:CC + | +LL | write_second(x, y); + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs new file mode 100644 index 00000000000..8ef3d23e804 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs @@ -0,0 +1,28 @@ +//! Make sure that a retag acts like a read for the data race model. +//! This is a retag/write race condition. +//! +//! This test is sensitive to the exact schedule so we disable preemption. +//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0 +#[derive(Copy, Clone)] +struct SendPtr(*mut u8); + +unsafe impl Send for SendPtr {} + +unsafe fn thread_1(SendPtr(p): SendPtr) { + let _r = &*p; +} + +unsafe fn thread_2(SendPtr(p): SendPtr) { + *p = 5; //~ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` +} + +fn main() { + let mut x = 0; + let p = std::ptr::addr_of_mut!(x); + let p = SendPtr(p); + + let t1 = std::thread::spawn(move || unsafe { thread_1(p) }); + let t2 = std::thread::spawn(move || unsafe { thread_2(p) }); + let _ = t1.join(); + let _ = t2.join(); +} diff --git a/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr new file mode 100644 index 00000000000..f2cdfe7c314 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + --> $DIR/retag-data-race.rs:LL:CC + | +LL | *p = 5; + | ^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> $DIR/retag-data-race.rs:LL:CC + | +LL | let _r = &*p; + | ^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): + = note: inside `thread_2` at $DIR/retag-data-race.rs:LL:CC +note: inside closure + --> $DIR/retag-data-race.rs:LL:CC + | +LL | let t2 = std::thread::spawn(move || unsafe { thread_2(p) }); + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs new file mode 100644 index 00000000000..6695d36306b --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Zmiri-tree-borrows + +// We invalidate a reference during a 2-phase borrow by doing a Foreign +// Write in between the initial reborrow and function entry. UB occurs +// on function entry when reborrow from a Disabled fails. +// This test would pass under Stacked Borrows, but Tree Borrows +// is more strict on 2-phase borrows. + +struct Foo(u64); +impl Foo { + #[rustfmt::skip] // rustfmt is wrong about which line contains an error + fn add(&mut self, n: u64) -> u64 { //~ ERROR: /read access through .* is forbidden/ + self.0 + n + } +} + +pub fn main() { + let mut f = Foo(0); + let inner = &mut f.0 as *mut u64; + let _res = f.add(unsafe { + let n = f.0; + // This is the access at fault, but it's not immediately apparent because + // the reference that got invalidated is not under a Protector. + *inner = 42; + n + }); +} diff --git a/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr new file mode 100644 index 00000000000..e511eb9cf8f --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr @@ -0,0 +1,26 @@ +error: Undefined Behavior: read access through <TAG> is forbidden because it is a child of <TAG> which is Disabled. + --> $DIR/write-during-2phase.rs:LL:CC + | +LL | fn add(&mut self, n: u64) -> u64 { + | ^^^^^^^^^ read access through <TAG> is forbidden because it is a child of <TAG> which is Disabled. + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `Foo::add` at $DIR/write-during-2phase.rs:LL:CC +note: inside `main` + --> $DIR/write-during-2phase.rs:LL:CC + | +LL | let _res = f.add(unsafe { + | ________________^ +LL | | let n = f.0; +LL | | // This is the access at fault, but it's not immediately apparent because +LL | | // the reference that got invalidated is not under a Protector. +LL | | *inner = 42; +LL | | n +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/pass/adjacent-allocs.rs b/src/tools/miri/tests/pass/adjacent-allocs.rs index 0051c62121c..cbf41d68b57 100644 --- a/src/tools/miri/tests/pass/adjacent-allocs.rs +++ b/src/tools/miri/tests/pass/adjacent-allocs.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance fn ensure_allocs_can_be_adjacent() { diff --git a/src/tools/miri/tests/pass/associated-const.rs b/src/tools/miri/tests/pass/associated-const.rs index 2ff08ffc4bf..331fbfcefde 100644 --- a/src/tools/miri/tests/pass/associated-const.rs +++ b/src/tools/miri/tests/pass/associated-const.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows trait Foo { const ID: i32; } diff --git a/src/tools/miri/tests/pass/assume_bug.rs b/src/tools/miri/tests/pass/assume_bug.rs index e14f875c022..662b9015088 100644 --- a/src/tools/miri/tests/pass/assume_bug.rs +++ b/src/tools/miri/tests/pass/assume_bug.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows fn main() { vec![()].into_iter(); } diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs index e3d80a78916..60b8ff87b59 100644 --- a/src/tools/miri/tests/pass/atomic.rs +++ b/src/tools/miri/tests/pass/atomic.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(strict_provenance, strict_provenance_atomic_ptr)] use std::sync::atomic::{ diff --git a/src/tools/miri/tests/pass/available-parallelism.rs b/src/tools/miri/tests/pass/available-parallelism.rs index eb4d09b1f54..77fb78424ba 100644 --- a/src/tools/miri/tests/pass/available-parallelism.rs +++ b/src/tools/miri/tests/pass/available-parallelism.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows fn main() { assert_eq!(std::thread::available_parallelism().unwrap().get(), 1); } diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs index ef432a86d46..155e3d74ab9 100644 --- a/src/tools/miri/tests/pass/box-custom-alloc.rs +++ b/src/tools/miri/tests/pass/box-custom-alloc.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![allow(incomplete_features)] // for trait upcasting #![feature(allocator_api, trait_upcasting)] diff --git a/src/tools/miri/tests/pass/box.rs b/src/tools/miri/tests/pass/box.rs index 7bbe7be516b..3bb481aab88 100644 --- a/src/tools/miri/tests/pass/box.rs +++ b/src/tools/miri/tests/pass/box.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance #![feature(ptr_internals)] fn main() { diff --git a/src/tools/miri/tests/pass/box.stderr b/src/tools/miri/tests/pass/box.stack.stderr index 4c2fb40e110..4c2fb40e110 100644 --- a/src/tools/miri/tests/pass/box.stderr +++ b/src/tools/miri/tests/pass/box.stack.stderr diff --git a/src/tools/miri/tests/pass/box.stdout b/src/tools/miri/tests/pass/box.stack.stdout index 230ef368da6..230ef368da6 100644 --- a/src/tools/miri/tests/pass/box.stdout +++ b/src/tools/miri/tests/pass/box.stack.stdout diff --git a/src/tools/miri/tests/pass/box.tree.stdout b/src/tools/miri/tests/pass/box.tree.stdout new file mode 100644 index 00000000000..230ef368da6 --- /dev/null +++ b/src/tools/miri/tests/pass/box.tree.stdout @@ -0,0 +1,3 @@ +pair_foo = PairFoo { fst: Foo(42), snd: Foo(1337) } +foo #0 = Foo(42) +foo #1 = Foo(1337) diff --git a/src/tools/miri/tests/pass/btreemap.rs b/src/tools/miri/tests/pass/btreemap.rs index 040c648d474..b7c0406becc 100644 --- a/src/tools/miri/tests/pass/btreemap.rs +++ b/src/tools/miri/tests/pass/btreemap.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; diff --git a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs index d76c23633da..ccf96b99672 100644 --- a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs +++ b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows // Check that you can cast between different pointers to trait objects // whose vtable have the same kind (both lengths, or both trait pointers). diff --git a/src/tools/miri/tests/pass/concurrency/channels.rs b/src/tools/miri/tests/pass/concurrency/channels.rs index 53b57942d76..43086756b03 100644 --- a/src/tools/miri/tests/pass/concurrency/channels.rs +++ b/src/tools/miri/tests/pass/concurrency/channels.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs index 19ea6c130bd..3bd1e542407 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.rs +++ b/src/tools/miri/tests/pass/concurrency/sync.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; diff --git a/src/tools/miri/tests/pass/concurrency/sync.stdout b/src/tools/miri/tests/pass/concurrency/sync.stack.stdout index f2c036a1735..f2c036a1735 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.stdout +++ b/src/tools/miri/tests/pass/concurrency/sync.stack.stdout diff --git a/src/tools/miri/tests/pass/concurrency/sync.tree.stdout b/src/tools/miri/tests/pass/concurrency/sync.tree.stdout new file mode 100644 index 00000000000..f2c036a1735 --- /dev/null +++ b/src/tools/miri/tests/pass/concurrency/sync.tree.stdout @@ -0,0 +1,20 @@ +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait diff --git a/src/tools/miri/tests/pass/concurrency/thread_locals.rs b/src/tools/miri/tests/pass/concurrency/thread_locals.rs index b19e56312f3..13c11b55775 100644 --- a/src/tools/miri/tests/pass/concurrency/thread_locals.rs +++ b/src/tools/miri/tests/pass/concurrency/thread_locals.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs index 7ccafec6037..bd06eec9cd5 100644 --- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs +++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs @@ -1,3 +1,6 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + use std::cell::RefCell; use std::thread; diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stdout b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stack.stdout index b7877820a0c..b7877820a0c 100644 --- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stdout +++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stack.stdout diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout new file mode 100644 index 00000000000..b7877820a0c --- /dev/null +++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout @@ -0,0 +1,5 @@ +Dropping: 8 (should be before 'Continue main 1'). +Dropping: 8 (should be before 'Continue main 1'). +Continue main 1. +Joining: 7 (should be before 'Continue main 2'). +Continue main 2. diff --git a/src/tools/miri/tests/pass/disable-alignment-check.rs b/src/tools/miri/tests/pass/disable-alignment-check.rs index 366aff4a9f8..fdcacc6cea4 100644 --- a/src/tools/miri/tests/pass/disable-alignment-check.rs +++ b/src/tools/miri/tests/pass/disable-alignment-check.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-disable-alignment-check fn main() { diff --git a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs index 256c72add92..94cf465e884 100644 --- a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs +++ b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/pass/extern_types.rs b/src/tools/miri/tests/pass/extern_types.rs index aa4c65ea892..7ac93577f0c 100644 --- a/src/tools/miri/tests/pass/extern_types.rs +++ b/src/tools/miri/tests/pass/extern_types.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance #![feature(extern_types)] extern "C" { diff --git a/src/tools/miri/tests/pass/extern_types.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr index 2e18f693058..2e18f693058 100644 --- a/src/tools/miri/tests/pass/extern_types.stderr +++ b/src/tools/miri/tests/pass/extern_types.stack.stderr diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index ce62fb0de04..fee5ca44ffb 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1,4 +1,5 @@ #![feature(stmt_expr_attributes)] +#![feature(round_ties_even)] #![allow(arithmetic_overflow)] use std::fmt::Debug; use std::hint::black_box; @@ -9,6 +10,7 @@ fn main() { more_casts(); ops(); nan_casts(); + rounding(); } // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. @@ -553,3 +555,31 @@ fn nan_casts() { assert!(nan1_32.is_nan()); assert!(nan2_32.is_nan()); } + +fn rounding() { + // Test cases taken from the library's tests for this feature + // f32 + assert_eq(2.5f32.round_ties_even(), 2.0f32); + assert_eq(1.0f32.round_ties_even(), 1.0f32); + assert_eq(1.3f32.round_ties_even(), 1.0f32); + assert_eq(1.5f32.round_ties_even(), 2.0f32); + assert_eq(1.7f32.round_ties_even(), 2.0f32); + assert_eq(0.0f32.round_ties_even(), 0.0f32); + assert_eq((-0.0f32).round_ties_even(), -0.0f32); + assert_eq((-1.0f32).round_ties_even(), -1.0f32); + assert_eq((-1.3f32).round_ties_even(), -1.0f32); + assert_eq((-1.5f32).round_ties_even(), -2.0f32); + assert_eq((-1.7f32).round_ties_even(), -2.0f32); + // f64 + assert_eq(2.5f64.round_ties_even(), 2.0f64); + assert_eq(1.0f64.round_ties_even(), 1.0f64); + assert_eq(1.3f64.round_ties_even(), 1.0f64); + assert_eq(1.5f64.round_ties_even(), 2.0f64); + assert_eq(1.7f64.round_ties_even(), 2.0f64); + assert_eq(0.0f64.round_ties_even(), 0.0f64); + assert_eq((-0.0f64).round_ties_even(), -0.0f64); + assert_eq((-1.0f64).round_ties_even(), -1.0f64); + assert_eq((-1.3f64).round_ties_even(), -1.0f64); + assert_eq((-1.5f64).round_ties_even(), -2.0f64); + assert_eq((-1.7f64).round_ties_even(), -2.0f64); +} diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/future-self-referential.rs index 6994def16a1..763eceeb6f0 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs +++ b/src/tools/miri/tests/pass/future-self-referential.rs @@ -1,3 +1,6 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + use std::future::*; use std::marker::PhantomPinned; use std::pin::*; diff --git a/src/tools/miri/tests/pass/generator.rs b/src/tools/miri/tests/pass/generator.rs index 06f48666c55..e059c7114e3 100644 --- a/src/tools/miri/tests/pass/generator.rs +++ b/src/tools/miri/tests/pass/generator.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(generators, generator_trait, never_type)] use std::fmt::Debug; diff --git a/src/tools/miri/tests/pass/hashmap.rs b/src/tools/miri/tests/pass/hashmap.rs index 29ddd6c59a1..7224e357c6f 100644 --- a/src/tools/miri/tests/pass/hashmap.rs +++ b/src/tools/miri/tests/pass/hashmap.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows use std::collections::HashMap; use std::hash::BuildHasher; diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs index e7ff90cb6bf..42b6f433420 100644 --- a/src/tools/miri/tests/pass/intptrcast.rs +++ b/src/tools/miri/tests/pass/intptrcast.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance use std::mem; diff --git a/src/tools/miri/tests/pass/linked-list.rs b/src/tools/miri/tests/pass/linked-list.rs index 7377f9f60b0..36df30070cb 100644 --- a/src/tools/miri/tests/pass/linked-list.rs +++ b/src/tools/miri/tests/pass/linked-list.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(linked_list_cursors)] use std::collections::LinkedList; diff --git a/src/tools/miri/tests/pass/many_shr_bor.rs b/src/tools/miri/tests/pass/many_shr_bor.rs index 376b41dd6e2..aa960aa147a 100644 --- a/src/tools/miri/tests/pass/many_shr_bor.rs +++ b/src/tools/miri/tests/pass/many_shr_bor.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows // Make sure validation can handle many overlapping shared borrows for different parts of a data structure use std::cell::RefCell; diff --git a/src/tools/miri/tests/pass/memleak_ignored.rs b/src/tools/miri/tests/pass/memleak_ignored.rs index 60e06094e17..bba3207ee4c 100644 --- a/src/tools/miri/tests/pass/memleak_ignored.rs +++ b/src/tools/miri/tests/pass/memleak_ignored.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-ignore-leaks fn main() { diff --git a/src/tools/miri/tests/pass/option_box_transmute_ptr.rs b/src/tools/miri/tests/pass/option_box_transmute_ptr.rs index 0786db1ef89..0ba6607a5d4 100644 --- a/src/tools/miri/tests/pass/option_box_transmute_ptr.rs +++ b/src/tools/miri/tests/pass/option_box_transmute_ptr.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows // This tests that the size of Option<Box<i32>> is the same as *const i32. fn option_box_deref() -> i32 { let val = Some(Box::new(42)); diff --git a/src/tools/miri/tests/pass/pointers.rs b/src/tools/miri/tests/pass/pointers.rs index d1340a04e04..1525ded6151 100644 --- a/src/tools/miri/tests/pass/pointers.rs +++ b/src/tools/miri/tests/pass/pointers.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance #![feature(ptr_metadata, const_raw_ptr_comparison)] diff --git a/src/tools/miri/tests/pass/provenance.rs b/src/tools/miri/tests/pass/provenance.rs index c411f748a06..835daa36cfc 100644 --- a/src/tools/miri/tests/pass/provenance.rs +++ b/src/tools/miri/tests/pass/provenance.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(strict_provenance)] #![feature(pointer_byte_offsets)] use std::{mem, ptr}; diff --git a/src/tools/miri/tests/pass/ptr_int_casts.rs b/src/tools/miri/tests/pass/ptr_int_casts.rs index 3044ac092b7..a2fcd098107 100644 --- a/src/tools/miri/tests/pass/ptr_int_casts.rs +++ b/src/tools/miri/tests/pass/ptr_int_casts.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance use std::mem; use std::ptr; diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs index ef7ff34d26b..35a52d0220b 100644 --- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs +++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] diff --git a/src/tools/miri/tests/pass/ptr_int_transmute.rs b/src/tools/miri/tests/pass/ptr_int_transmute.rs index ba50480c539..d99c25413e6 100644 --- a/src/tools/miri/tests/pass/ptr_int_transmute.rs +++ b/src/tools/miri/tests/pass/ptr_int_transmute.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows // Test what happens when we read parts of a pointer. // Related to <https://github.com/rust-lang/rust/issues/69488>. fn ptr_partial_read() { diff --git a/src/tools/miri/tests/pass/rc.rs b/src/tools/miri/tests/pass/rc.rs index 569dbc459a5..6375abcd232 100644 --- a/src/tools/miri/tests/pass/rc.rs +++ b/src/tools/miri/tests/pass/rc.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/src/tools/miri/tests/pass/send-is-not-static-par-for.rs b/src/tools/miri/tests/pass/send-is-not-static-par-for.rs index 642f75ecc09..458312508d2 100644 --- a/src/tools/miri/tests/pass/send-is-not-static-par-for.rs +++ b/src/tools/miri/tests/pass/send-is-not-static-par-for.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows use std::sync::Mutex; fn par_for<I, F>(iter: I, f: F) diff --git a/src/tools/miri/tests/pass/slices.rs b/src/tools/miri/tests/pass/slices.rs index a56b97a5088..a99e921150b 100644 --- a/src/tools/miri/tests/pass/slices.rs +++ b/src/tools/miri/tests/pass/slices.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(slice_as_chunks)] diff --git a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs index 3ca937ae13d..74761a89cb9 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs @@ -7,7 +7,7 @@ use std::{ extern "Rust" { fn miri_get_alloc_id(ptr: *const u8) -> u64; - fn miri_print_borrow_stacks(alloc_id: u64); + fn miri_print_borrow_state(alloc_id: u64, show_unnamed: bool); } fn get_alloc_id(ptr: *const u8) -> u64 { @@ -15,7 +15,9 @@ fn get_alloc_id(ptr: *const u8) -> u64 { } fn print_borrow_stacks(alloc_id: u64) { - unsafe { miri_print_borrow_stacks(alloc_id) } + unsafe { + miri_print_borrow_state(alloc_id, /* ignored: show_unnamed */ false) + } } fn main() { diff --git a/src/tools/miri/tests/pass/threadleak_ignored.rs b/src/tools/miri/tests/pass/threadleak_ignored.rs index a5f81573e96..d4899856194 100644 --- a/src/tools/miri/tests/pass/threadleak_ignored.rs +++ b/src/tools/miri/tests/pass/threadleak_ignored.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-ignore-leaks //! Test that leaking threads works, and that their destructors are not executed. diff --git a/src/tools/miri/tests/pass/threadleak_ignored.stderr b/src/tools/miri/tests/pass/threadleak_ignored.stack.stderr index 7557f49c758..7557f49c758 100644 --- a/src/tools/miri/tests/pass/threadleak_ignored.stderr +++ b/src/tools/miri/tests/pass/threadleak_ignored.stack.stderr diff --git a/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr b/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr new file mode 100644 index 00000000000..7557f49c758 --- /dev/null +++ b/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr @@ -0,0 +1 @@ +Dropping 0 diff --git a/src/tools/miri/tests/pass/transmute_ptr.rs b/src/tools/miri/tests/pass/transmute_ptr.rs index fd9d457e440..ce6d86b7068 100644 --- a/src/tools/miri/tests/pass/transmute_ptr.rs +++ b/src/tools/miri/tests/pass/transmute_ptr.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(strict_provenance)] use std::{mem, ptr}; diff --git a/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs b/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs new file mode 100644 index 00000000000..af52f53791a --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Counterpart to tests/fail/tree-borrows/write-during-2phase.rs, +// this is the opposite situation: the Write is not problematic because +// the Protector has not yet been added and the Reserved has interior +// mutability. +use core::cell::Cell; + +trait Thing: Sized { + fn do_the_thing(&mut self, _s: i32) {} +} +impl<T> Thing for Cell<T> {} + +fn main() { + let mut x = Cell::new(1); + let l = &x; + + x.do_the_thing({ + // Several Foreign accesses (both Reads and Writes) to the location + // being reborrowed. Reserved + unprotected + interior mut + // makes the pointer immune to everything as long as all accesses + // are child accesses to its parent pointer x. + x.set(3); + l.set(4); + x.get() + l.get() + }); +} diff --git a/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs new file mode 100644 index 00000000000..1bd94c6df67 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +use std::cell::UnsafeCell; + +// UnsafeCells use the parent tag, so it is possible to use them with +// few restrictions when only among themselves. +fn main() { + unsafe { + let data = &mut UnsafeCell::new(0u8); + name!(data.get(), "data"); + let x = &*data; + name!(x.get(), "x"); + let y = &*data; + name!(y.get(), "y"); + let alloc_id = alloc_id!(data.get()); + print_state!(alloc_id); + // y and x tolerate alternating Writes + *y.get() = 1; + *x.get() = 2; + *y.get() = 3; + *x.get() = 4; + print_state!(alloc_id); + } +} diff --git a/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr new file mode 100644 index 00000000000..d4bc822b4bb --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr @@ -0,0 +1,10 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Re*| └────<TAG=data,x,y> +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └────<TAG=data,x,y> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs b/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs new file mode 100644 index 00000000000..23250d6e6df --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs @@ -0,0 +1,29 @@ +//@compile-flags: -Zmiri-tree-borrows + +// copy_nonoverlapping works regardless of the order in which we construct +// the arguments. +pub fn main() { + test_to_from(); + test_from_to(); +} + +fn test_to_from() { + unsafe { + let data = &mut [0u64, 1]; + let to = data.as_mut_ptr().add(1); + let from = data.as_ptr(); + std::ptr::copy_nonoverlapping(from, to, 1); + } +} + +// Stacked Borrows would not have liked this one because the `as_mut_ptr` reborrow +// invalidates the earlier pointer obtained from `as_ptr`, but Tree Borrows is fine +// with it. +fn test_from_to() { + unsafe { + let data = &mut [0u64, 1]; + let from = data.as_ptr(); + let to = data.as_mut_ptr().add(1); + std::ptr::copy_nonoverlapping(from, to, 1); + } +} diff --git a/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs new file mode 100644 index 00000000000..76bbc73e662 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs @@ -0,0 +1,32 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +// Check that a protector goes back to normal behavior when the function +// returns. +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +fn main() { + unsafe { + let data = &mut 0u8; + name!(data); + let alloc_id = alloc_id!(data); + let x = &mut *data; + name!(x); + print_state!(alloc_id); + do_nothing(x); // creates then removes a Protector for a child of x + let y = &mut *data; + name!(y); + print_state!(alloc_id); + // Invalidates the previous reborrow, but its Protector has been removed. + *y = 1; + print_state!(alloc_id); + } +} + +unsafe fn do_nothing(x: &mut u8) { + name!(x, "callee:x"); + name!(x=>1, "caller:x"); + let alloc_id = alloc_id!(x); + print_state!(alloc_id); +} diff --git a/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr new file mode 100644 index 00000000000..d08d6948320 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr @@ -0,0 +1,32 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=data> +| Res| └────<TAG=x> +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=data> +| Res| └─┬──<TAG=x> +| Res| └─┬──<TAG=caller:x> +| Res| └────<TAG=callee:x> Strongly protected +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=data> +| Res| ├─┬──<TAG=x> +| Res| │ └─┬──<TAG=caller:x> +| Res| │ └────<TAG=callee:x> +| Res| └────<TAG=y> +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └─┬──<TAG=data> +| Dis| ├─┬──<TAG=x> +| Dis| │ └─┬──<TAG=caller:x> +| Dis| │ └────<TAG=callee:x> +| Act| └────<TAG=y> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/formatting.rs b/src/tools/miri/tests/pass/tree-borrows/formatting.rs new file mode 100644 index 00000000000..9021c417638 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/formatting.rs @@ -0,0 +1,73 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +// Check the formatting of the trees. +fn main() { + unsafe { + alignment_check(); + structure_check(); + } +} + +// Alignment check: we split the array at indexes with different amounts of +// decimal digits to verify proper padding. +unsafe fn alignment_check() { + let data: &mut [u8] = &mut [0; 1024]; + name!(data.as_ptr()=>2, "data"); + let alloc_id = alloc_id!(data.as_ptr()); + let x = &mut data[1]; + name!(x as *mut _, "data[1]"); + *x = 1; + let x = &mut data[10]; + name!(x as *mut _, "data[10]"); + *x = 1; + let x = &mut data[100]; + name!(x as *mut _, "data[100]"); + *x = 1; + let _val = data[100]; // So that the above is Frz + let x = &mut data[1000]; + name!(x as *mut _, "data[1000]"); + *x = 1; + print_state!(alloc_id); +} + +// Tree structure check: somewhat complex organization of reborrows. +unsafe fn structure_check() { + let x = &0u8; + name!(x); + let xa = &*x; + name!(xa); + let xb = &*x; + name!(xb); + let xc = &*x; + name!(xc); + let xaa = &*xa; + name!(xaa); + let xab = &*xa; + name!(xab); + let xba = &*xb; + name!(xba); + let xbaa = &*xba; + name!(xbaa); + let xbaaa = &*xbaa; + name!(xbaaa); + let xbaaaa = &*xbaaa; + name!(xbaaaa); + let xca = &*xc; + name!(xca); + let xcb = &*xc; + name!(xcb); + let xcaa = &*xca; + name!(xcaa); + let xcab = &*xca; + name!(xcab); + let xcba = &*xcb; + name!(xcba); + let xcbb = &*xcb; + name!(xcbb); + let alloc_id = alloc_id!(x); + print_state!(alloc_id); +} diff --git a/src/tools/miri/tests/pass/tree-borrows/formatting.stderr b/src/tools/miri/tests/pass/tree-borrows/formatting.stderr new file mode 100644 index 00000000000..a59775cf21f --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/formatting.stderr @@ -0,0 +1,29 @@ +───────────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1.. 2.. 10.. 11..100..101..1000..1001..1024 +| Res| Act| Res| Act| Res| Act| Res| Act| Res| └─┬──<TAG=data> +|----| Act|----|?Dis|----|?Dis| ----| ?Dis| ----| ├────<TAG=data[1]> +|----|----|----| Act|----|?Dis| ----| ?Dis| ----| ├────<TAG=data[10]> +|----|----|----|----|----| Frz| ----| ?Dis| ----| ├────<TAG=data[100]> +|----|----|----|----|----|----| ----| Act| ----| └────<TAG=data[1000]> +───────────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Frz| └─┬──<TAG=x> +| Frz| ├─┬──<TAG=xa> +| Frz| │ ├────<TAG=xaa> +| Frz| │ └────<TAG=xab> +| Frz| ├─┬──<TAG=xb> +| Frz| │ └─┬──<TAG=xba> +| Frz| │ └─┬──<TAG=xbaa> +| Frz| │ └─┬──<TAG=xbaaa> +| Frz| │ └────<TAG=xbaaaa> +| Frz| └─┬──<TAG=xc> +| Frz| ├─┬──<TAG=xca> +| Frz| │ ├────<TAG=xcaa> +| Frz| │ └────<TAG=xcab> +| Frz| └─┬──<TAG=xcb> +| Frz| ├────<TAG=xcba> +| Frz| └────<TAG=xcbb> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs b/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs new file mode 100644 index 00000000000..4daf06c777e --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs @@ -0,0 +1,14 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Tree Borrows has no issue with several mutable references existing +// at the same time, as long as they are used only immutably. +// I.e. multiple Reserved can coexist. +pub fn main() { + unsafe { + let base = &mut 42u64; + let r1 = &mut *(base as *mut u64); + let r2 = &mut *(base as *mut u64); + let _l = *r1; + let _l = *r2; + } +} diff --git a/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs new file mode 100644 index 00000000000..e3f3f2d4032 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs @@ -0,0 +1,24 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +// To check that a reborrow is counted as a Read access, we use a reborrow +// with no additional Read to Freeze an Active pointer. + +fn main() { + unsafe { + let parent = &mut 0u8; + name!(parent); + let alloc_id = alloc_id!(parent); + let x = &mut *parent; + name!(x); + *x = 0; // x is now Active + print_state!(alloc_id); + let y = &mut *parent; + name!(y); + // Check in the debug output that x has been Frozen by the reborrow + print_state!(alloc_id); + } +} diff --git a/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr new file mode 100644 index 00000000000..b9c52c20640 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr @@ -0,0 +1,13 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └─┬──<TAG=parent> +| Act| └────<TAG=x> +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └─┬──<TAG=parent> +| Frz| ├────<TAG=x> +| Res| └────<TAG=y> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/reserved.rs b/src/tools/miri/tests/pass/tree-borrows/reserved.rs new file mode 100644 index 00000000000..d8a8c27568d --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/reserved.rs @@ -0,0 +1,127 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; +use utils::miri_extern::miri_write_to_stderr; + +use std::cell::UnsafeCell; + +// We exhaustively check that Reserved behaves as we want under all of the +// following conditions: +// - with or without interior mutability +// - with or without a protector +// - for a foreign read or write +// Of these cases, those in this file are the ones that must not cause +// immediate UB, and those that do are in tests/fail/tree-borrows/reserved/ +// and are the combinations [_ + protected + write] + +fn main() { + unsafe { + cell_protected_read(); + cell_unprotected_read(); + cell_unprotected_write(); + int_protected_read(); + int_unprotected_read(); + int_unprotected_write(); + } +} + +unsafe fn print(msg: &str) { + miri_write_to_stderr(msg.as_bytes()); + miri_write_to_stderr("\n".as_bytes()); +} + +unsafe fn read_second<T>(x: &mut T, y: *mut u8) { + name!(x as *mut T as *mut u8=>1, "caller:x"); + name!(x as *mut T as *mut u8, "callee:x"); + name!(y, "caller:y"); + name!(y, "callee:y"); + let _val = *y; +} + +// Foreign Read on a interior mutable Protected Reserved turns it Frozen. +unsafe fn cell_protected_read() { + print("[interior mut + protected] Foreign Read: Re* -> Frz"); + let base = &mut UnsafeCell::new(0u8); + name!(base.get(), "base"); + let alloc_id = alloc_id!(base.get()); + let x = &mut *(base as *mut UnsafeCell<u8>); + name!(x.get(), "x"); + let y = (&mut *base).get(); + name!(y); + read_second(x, y); // Foreign Read for callee:x + print_state!(alloc_id); +} + +// Foreign Read on an interior mutable pointer is a noop. +unsafe fn cell_unprotected_read() { + print("[interior mut] Foreign Read: Re* -> Re*"); + let base = &mut UnsafeCell::new(0u64); + name!(base.get(), "base"); + let alloc_id = alloc_id!(base.get()); + let x = &mut *(base as *mut UnsafeCell<_>); + name!(x.get(), "x"); + let y = (&mut *base).get(); + name!(y); + let _val = *y; // Foreign Read for x + print_state!(alloc_id); +} + +// Foreign Write on an interior mutable pointer is a noop. +// Also y must become Active. +unsafe fn cell_unprotected_write() { + print("[interior mut] Foreign Write: Re* -> Re*"); + let base = &mut UnsafeCell::new(0u64); + name!(base.get(), "base"); + let alloc_id = alloc_id!(base.get()); + let x = &mut *(base as *mut UnsafeCell<u64>); + name!(x.get(), "x"); + let y = (&mut *base).get(); + name!(y); + *y = 1; // Foreign Write for x + print_state!(alloc_id); +} + +// Foreign Read on a Protected Reserved turns it Frozen. +unsafe fn int_protected_read() { + print("[protected] Foreign Read: Res -> Frz"); + let base = &mut 0u8; + let alloc_id = alloc_id!(base); + name!(base); + let x = &mut *(base as *mut u8); + name!(x); + let y = (&mut *base) as *mut u8; + name!(y); + read_second(x, y); // Foreign Read for callee:x + print_state!(alloc_id); +} + +// Foreign Read on a Reserved is a noop. +// Also y must become Active. +unsafe fn int_unprotected_read() { + print("[] Foreign Read: Res -> Res"); + let base = &mut 0u8; + name!(base); + let alloc_id = alloc_id!(base); + let x = &mut *(base as *mut u8); + name!(x); + let y = (&mut *base) as *mut u8; + name!(y); + let _val = *y; // Foreign Read for x + print_state!(alloc_id); +} + +// Foreign Write on a Reserved turns it Disabled. +unsafe fn int_unprotected_write() { + print("[] Foreign Write: Res -> Dis"); + let base = &mut 0u8; + name!(base); + let alloc_id = alloc_id!(base); + let x = &mut *(base as *mut u8); + name!(x); + let y = (&mut *base) as *mut u8; + name!(y); + *y = 1; // Foreign Write for x + print_state!(alloc_id); +} diff --git a/src/tools/miri/tests/pass/tree-borrows/reserved.stderr b/src/tools/miri/tests/pass/tree-borrows/reserved.stderr new file mode 100644 index 00000000000..d76ee0f8266 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/reserved.stderr @@ -0,0 +1,52 @@ +[interior mut + protected] Foreign Read: Re* -> Frz +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Re*| └─┬──<TAG=base> +| Re*| ├─┬──<TAG=x> +| Re*| │ └─┬──<TAG=caller:x> +| Frz| │ └────<TAG=callee:x> +| Re*| └────<TAG=y,caller:y,callee:y> +────────────────────────────────────────────────────────────────────── +[interior mut] Foreign Read: Re* -> Re* +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 8 +| Re*| └─┬──<TAG=base> +| Re*| ├────<TAG=x> +| Re*| └────<TAG=y> +────────────────────────────────────────────────────────────────────── +[interior mut] Foreign Write: Re* -> Re* +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 8 +| Act| └─┬──<TAG=base> +| Re*| ├────<TAG=x> +| Act| └────<TAG=y> +────────────────────────────────────────────────────────────────────── +[protected] Foreign Read: Res -> Frz +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=base> +| Res| ├─┬──<TAG=x> +| Res| │ └─┬──<TAG=caller:x> +| Frz| │ └────<TAG=callee:x> +| Res| └────<TAG=y,caller:y,callee:y> +────────────────────────────────────────────────────────────────────── +[] Foreign Read: Res -> Res +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=base> +| Res| ├────<TAG=x> +| Res| └────<TAG=y> +────────────────────────────────────────────────────────────────────── +[] Foreign Write: Res -> Dis +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └─┬──<TAG=base> +| Dis| ├────<TAG=x> +| Act| └────<TAG=y> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs b/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs new file mode 100644 index 00000000000..e1a9334ab54 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs @@ -0,0 +1,13 @@ +//@compile-flags: -Zmiri-tree-borrows + +use core::cell::UnsafeCell; +use core::mem; + +fn main() { + unsafe { + let x = &0i32; + // As long as we only read, transmuting this to UnsafeCell should be fine. + let cell_x: &UnsafeCell<i32> = mem::transmute(&x); + let _val = *cell_x.get(); + } +} diff --git a/src/tools/miri/tests/pass/unsized.rs b/src/tools/miri/tests/pass/unsized.rs index d9beac4327d..c9046dc3c76 100644 --- a/src/tools/miri/tests/pass/unsized.rs +++ b/src/tools/miri/tests/pass/unsized.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(unsized_tuple_coercion)] #![feature(unsized_fn_params)] diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs index 30a28bc5803..06ec2f99172 100644 --- a/src/tools/miri/tests/pass/vec.rs +++ b/src/tools/miri/tests/pass/vec.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(iter_advance_by, iter_next_chunk)] diff --git a/src/tools/miri/tests/pass/vecdeque.rs b/src/tools/miri/tests/pass/vecdeque.rs index 6f56f9d103e..dfbf9bb83c1 100644 --- a/src/tools/miri/tests/pass/vecdeque.rs +++ b/src/tools/miri/tests/pass/vecdeque.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance use std::collections::VecDeque; diff --git a/src/tools/miri/tests/pass/vecdeque.stdout b/src/tools/miri/tests/pass/vecdeque.stack.stdout index 63de960ee2b..63de960ee2b 100644 --- a/src/tools/miri/tests/pass/vecdeque.stdout +++ b/src/tools/miri/tests/pass/vecdeque.stack.stdout diff --git a/src/tools/miri/tests/pass/vecdeque.tree.stdout b/src/tools/miri/tests/pass/vecdeque.tree.stdout new file mode 100644 index 00000000000..63de960ee2b --- /dev/null +++ b/src/tools/miri/tests/pass/vecdeque.tree.stdout @@ -0,0 +1,2 @@ +[2, 2] Iter([2, 2], []) +Iter([], []) diff --git a/src/tools/miri/tests/utils/macros.rs b/src/tools/miri/tests/utils/macros.rs new file mode 100644 index 00000000000..de223410fba --- /dev/null +++ b/src/tools/miri/tests/utils/macros.rs @@ -0,0 +1,61 @@ +#![allow(unused_macros)] +#![allow(unused_macro_rules)] +#![allow(unused_imports)] + +/// `alloc_id!(ptr)`: obtain the allocation id from a pointer. +/// +/// `ptr` should be any pointer or reference that can be converted with `_ as *const u8`. +/// +/// The id obtained can be passed directly to `print_state!`. +macro_rules! alloc_id { + ($ptr:expr) => { + crate::utils::miri_extern::miri_get_alloc_id($ptr as *const u8 as *const ()) + }; +} + +/// `print_state!(alloc_id, show_unnamed)`: print the internal state of the borrow +/// tracker (stack or tree). +/// +/// `alloc_id` should be obtained from `alloc_id!`. +/// +/// `show_unnamed` is an optional boolean that determines if Tree Borrows displays +/// tags that have not been given a name. Defaults to `false`. +macro_rules! print_state { + ($alloc_id:expr) => { + crate::utils::macros::print_state!($alloc_id, false); + }; + ($alloc_id:expr, $show:expr) => { + crate::utils::miri_extern::miri_print_borrow_state($alloc_id, $show); + }; +} + +/// `name!(ptr => nth_parent, name)`: associate `name` to the `nth_parent` of `ptr`. +/// +/// `ptr` should be any pointer or reference that can be converted with `_ as *const u8`. +/// +/// `nth_parent` is an optional `u8` that defaults to 0. The corresponding ancestor +/// of the tag of `ptr` will be searched: 0 for `ptr` itself, 1 for the direct parent +/// of `ptr`, 2 for the grandparent, etc. If `nth_parent` is not specified, +/// then `=>` should also not be included. +/// +/// `name` is an optional string that will be used as the name. Defaults to +/// `stringify!($ptr)` the name of `ptr` in the source code. +macro_rules! name { + ($ptr:expr, $name:expr) => { + crate::utils::macros::name!($ptr => 0, $name); + }; + ($ptr:expr) => { + crate::utils::macros::name!($ptr => 0, stringify!($ptr)); + }; + ($ptr:expr => $nb:expr) => { + crate::utils::macros::name!($ptr => $nb, stringify!($ptr)); + }; + ($ptr:expr => $nb:expr, $name:expr) => { + let name = $name.as_bytes(); + crate::utils::miri_extern::miri_pointer_name($ptr as *const u8 as *const (), $nb, name); + }; +} + +pub(crate) use alloc_id; +pub(crate) use name; +pub(crate) use print_state; diff --git a/src/tools/miri/tests/utils/miri_extern.rs b/src/tools/miri/tests/utils/miri_extern.rs new file mode 100644 index 00000000000..6c4298c613b --- /dev/null +++ b/src/tools/miri/tests/utils/miri_extern.rs @@ -0,0 +1,142 @@ +#![allow(dead_code)] + +#[repr(C)] +/// Layout of the return value of `miri_resolve_frame`, +/// with fields in the exact same order. +pub struct MiriFrame { + // The size of the name of the function being executed, encoded in UTF-8 + pub name_len: usize, + // The size of filename of the function being executed, encoded in UTF-8 + pub filename_len: usize, + // The line number currently being executed in `filename`, starting from '1'. + pub lineno: u32, + // The column number currently being executed in `filename`, starting from '1'. + pub colno: u32, + // The function pointer to the function currently being executed. + // This can be compared against function pointers obtained by + // casting a function (e.g. `my_fn as *mut ()`) + pub fn_ptr: *mut (), +} + +#[cfg(miri)] +extern "Rust" { + /// Miri-provided extern function to mark the block `ptr` points to as a "root" + /// for some static memory. This memory and everything reachable by it is not + /// considered leaking even if it still exists when the program terminates. + /// + /// `ptr` has to point to the beginning of an allocated block. + pub fn miri_static_root(ptr: *const u8); + + // Miri-provided extern function to get the amount of frames in the current backtrace. + // The `flags` argument must be `0`. + pub fn miri_backtrace_size(flags: u64) -> usize; + + /// Miri-provided extern function to obtain a backtrace of the current call stack. + /// This writes a slice of pointers into `buf` - each pointer is an opaque value + /// that is only useful when passed to `miri_resolve_frame`. + /// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space. + /// The `flags` argument must be `1`. + pub fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); + + /// Miri-provided extern function to resolve a frame pointer obtained + /// from `miri_get_backtrace`. The `flags` argument must be `1`. + /// + /// This function can be called on any thread (not just the one which obtained `frame`). + pub fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; + + /// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`. + /// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`. + /// The flags argument must be `0`. + pub fn miri_resolve_frame_names( + ptr: *mut (), + flags: u64, + name_buf: *mut u8, + filename_buf: *mut u8, + ); + + /// Miri-provided extern function to begin unwinding with the given payload. + /// + /// This is internal and unstable and should not be used; we give it here + /// just to be complete. + pub fn miri_start_panic(payload: *mut u8) -> !; + + /// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer + /// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort. + /// + /// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because + /// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation. + /// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so + /// inherits all of its instability. + pub fn miri_get_alloc_id(ptr: *const ()) -> u64; + + /// Miri-provided extern function to print (from the interpreter, not the program) the contents of all + /// borrows in an allocation. + /// + /// If Stacked Borrows is running, this prints all the stacks. The leftmost tag is the bottom of the stack. + /// + /// If Tree borrows is running, this prints on the left the permissions of each tag on each range, + /// an on the right the tree structure of the tags. If some tags were named via `miri_pointer_name`, + /// their names appear here. + /// + /// If additionally `show_unnamed` is `false` then tags that did *not* receive a name will be hidden. + /// Ensure that either the important tags have been named, or `show_unnamed = true`. + /// Note: as Stacked Borrows does not have tag names at all, `show_unnamed` is ignored and all tags are shown. + /// In general, unless you strongly want some tags to be hidden (as is the case in `tree-borrows` tests), + /// `show_unnamed = true` should be the default. + /// + /// The format of what this emits is unstable and may change at any time. In particular, users should be + /// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of + /// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC. + /// + /// This function is extremely unstable. At any time the format of its output may change, its signature may + /// change, or it may be removed entirely. + pub fn miri_print_borrow_state(alloc_id: u64, show_unnamed: bool); + + /// Miri-provided extern function to associate a name to the nth parent of a tag. + /// Typically the name given would be the name of the program variable that holds the pointer. + /// Unreachable tags can still be named by using nonzero `nth_parent` and a child tag. + /// + /// This function does nothing under Stacked Borrows, since Stacked Borrows's implementation + /// of `miri_print_borrow_state` does not show the names. + /// + /// Under Tree Borrows, the names also appear in error messages. + pub fn miri_pointer_name(ptr: *const (), nth_parent: u8, name: &[u8]); + + /// Miri-provided extern function to print (from the interpreter, not the + /// program) the contents of a section of program memory, as bytes. Bytes + /// written using this function will emerge from the interpreter's stdout. + pub fn miri_write_to_stdout(bytes: &[u8]); + + /// Miri-provided extern function to print (from the interpreter, not the + /// program) the contents of a section of program memory, as bytes. Bytes + /// written using this function will emerge from the interpreter's stderr. + pub fn miri_write_to_stderr(bytes: &[u8]); + + /// Miri-provided extern function to allocate memory from the interpreter. + /// + /// This is useful when no fundamental way of allocating memory is + /// available, e.g. when using `no_std` + `alloc`. + pub fn miri_alloc(size: usize, align: usize) -> *mut u8; + + /// Miri-provided extern function to deallocate memory. + pub fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); + + /// Convert a path from the host Miri runs on to the target Miri interprets. + /// Performs conversion of path separators as needed. + /// + /// Usually Miri performs this kind of conversion automatically. However, manual conversion + /// might be necessary when reading an environment variable that was set on the host + /// (such as TMPDIR) and using it as a target path. + /// + /// Only works with isolation disabled. + /// + /// `in` must point to a null-terminated string, and will be read as the input host path. + /// `out` must point to at least `out_size` many bytes, and the result will be stored there + /// with a null terminator. + /// Returns 0 if the `out` buffer was large enough, and the required size otherwise. + pub fn miri_host_to_target_path( + path: *const std::ffi::c_char, + out: *mut std::ffi::c_char, + out_size: usize, + ) -> usize; +} diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs new file mode 100644 index 00000000000..e1ea77e4df8 --- /dev/null +++ b/src/tools/miri/tests/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod macros; +pub mod miri_extern; diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index fc77515b63b..25242c6028a 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -169,9 +169,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.88.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df80a3fbc1f0e59f560eeeebca94bf655566a8ad3023c210a109deb6056455a" +checksum = "ea176c50987dc4765961aa165001e8eb5a722a26308c5797a47303ea91686aab" dependencies = [ "proc-macro2", "quote", @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.88.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f39e5272016916956298cceea5147006f897972c274a768ed4d6e074efe5d3fb" +checksum = "473b480241695428c14e8f84f1c9a47ef232450a50faf3a4041e5c9dc11e0a3b" dependencies = [ "bitflags", "chalk-derive", @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.88.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d60b42ad7478d3e027e2f9ea4e99fbbb8fdee0c8c3cf068be269f57e603618" +checksum = "6764b4fe67cac3a3758185084efbfbd39bf0352795824ba849ddd2b64cd4bb28" dependencies = [ "chalk-derive", "chalk-ir", @@ -205,9 +205,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.88.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab30620ea5b36819525eaab2204f4b8e1842fc7ee36826424a28bef59ae7fecf" +checksum = "55a7e6160966eceb6e7dcc2f479a2af4c477aaf5bccbc640d82515995ab1a6cc" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/src/tools/rust-analyzer/bench_data/numerous_macro_rules b/src/tools/rust-analyzer/bench_data/numerous_macro_rules index bf89ed594f7..7610a3ae1e3 100644 --- a/src/tools/rust-analyzer/bench_data/numerous_macro_rules +++ b/src/tools/rust-analyzer/bench_data/numerous_macro_rules @@ -341,8 +341,8 @@ macro_rules! __ra_macro_fixture339 {($name : ident )=>{ impl Clone for $name macro_rules! __ra_macro_fixture340 {([$($stack : tt )*])=>{$($stack )* }; ([$($stack : tt )*]{$($tail : tt )* })=>{$($stack )* { remove_sections_inner ! ([]$($tail )*); }}; ([$($stack : tt )*]$t : tt $($tail : tt )*)=>{ remove_sections ! ([$($stack )* $t ]$($tail )*); }; } macro_rules! __ra_macro_fixture341 {($t : ty ,$z : expr )=>{ impl Zero for $t { fn zero ()-> Self {$z as $t } fn is_zero (& self )-> bool { self == & Self :: zero ()}}}; } macro_rules! __ra_macro_fixture342 {($($ident : ident ),* $(,)?)=>{$(# [ allow ( bad_style )] pub const $ident : super :: Name = super :: Name :: new_inline ( stringify ! ($ident )); )* }; } -macro_rules! __ra_macro_fixture343 {($($trait : ident =>$expand : ident ),* )=>{# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum BuiltinDeriveExpander {$($trait ),* } impl BuiltinDeriveExpander { pub fn expand (& self , db : & dyn AstDatabase , id : LazyMacroId , tt : & tt :: Subtree , )-> Result < tt :: Subtree , mbe :: ExpandError > { let expander = match * self {$(BuiltinDeriveExpander ::$trait =>$expand , )* }; expander ( db , id , tt )} fn find_by_name ( name : & name :: Name )-> Option < Self > { match name {$(id if id == & name :: name ! [$trait ]=> Some ( BuiltinDeriveExpander ::$trait ), )* _ => None , }}}}; } -macro_rules! __ra_macro_fixture344 {( LAZY : $(($name : ident , $kind : ident )=>$expand : ident ),* , EAGER : $(($e_name : ident , $e_kind : ident )=>$e_expand : ident ),* )=>{# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum BuiltinFnLikeExpander {$($kind ),* }# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum EagerExpander {$($e_kind ),* } impl BuiltinFnLikeExpander { pub fn expand (& self , db : & dyn AstDatabase , id : LazyMacroId , tt : & tt :: Subtree , )-> ExpandResult < tt :: Subtree > { let expander = match * self {$(BuiltinFnLikeExpander ::$kind =>$expand , )* }; expander ( db , id , tt )}} impl EagerExpander { pub fn expand (& self , db : & dyn AstDatabase , arg_id : EagerMacroId , tt : & tt :: Subtree , )-> ExpandResult < Option < ( tt :: Subtree , FragmentKind )>> { let expander = match * self {$(EagerExpander ::$e_kind =>$e_expand , )* }; expander ( db , arg_id , tt )}} fn find_by_name ( ident : & name :: Name )-> Option < Either < BuiltinFnLikeExpander , EagerExpander >> { match ident {$(id if id == & name :: name ! [$name ]=> Some ( Either :: Left ( BuiltinFnLikeExpander ::$kind )), )* $(id if id == & name :: name ! [$e_name ]=> Some ( Either :: Right ( EagerExpander ::$e_kind )), )* _ => return None , }}}; } +macro_rules! __ra_macro_fixture343 {($($trait : ident =>$expand : ident ),* )=>{# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum BuiltinDeriveExpander {$($trait ),* } impl BuiltinDeriveExpander { pub fn expand (& self , db : & dyn ExpandDatabase , id : LazyMacroId , tt : & tt :: Subtree , )-> Result < tt :: Subtree , mbe :: ExpandError > { let expander = match * self {$(BuiltinDeriveExpander ::$trait =>$expand , )* }; expander ( db , id , tt )} fn find_by_name ( name : & name :: Name )-> Option < Self > { match name {$(id if id == & name :: name ! [$trait ]=> Some ( BuiltinDeriveExpander ::$trait ), )* _ => None , }}}}; } +macro_rules! __ra_macro_fixture344 {( LAZY : $(($name : ident , $kind : ident )=>$expand : ident ),* , EAGER : $(($e_name : ident , $e_kind : ident )=>$e_expand : ident ),* )=>{# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum BuiltinFnLikeExpander {$($kind ),* }# [ derive ( Debug , Clone , Copy , PartialEq , Eq , Hash )] pub enum EagerExpander {$($e_kind ),* } impl BuiltinFnLikeExpander { pub fn expand (& self , db : & dyn ExpandDatabase , id : LazyMacroId , tt : & tt :: Subtree , )-> ExpandResult < tt :: Subtree > { let expander = match * self {$(BuiltinFnLikeExpander ::$kind =>$expand , )* }; expander ( db , id , tt )}} impl EagerExpander { pub fn expand (& self , db : & dyn ExpandDatabase , arg_id : EagerMacroId , tt : & tt :: Subtree , )-> ExpandResult < Option < ( tt :: Subtree , FragmentKind )>> { let expander = match * self {$(EagerExpander ::$e_kind =>$e_expand , )* }; expander ( db , arg_id , tt )}} fn find_by_name ( ident : & name :: Name )-> Option < Either < BuiltinFnLikeExpander , EagerExpander >> { match ident {$(id if id == & name :: name ! [$name ]=> Some ( Either :: Left ( BuiltinFnLikeExpander ::$kind )), )* $(id if id == & name :: name ! [$e_name ]=> Some ( Either :: Right ( EagerExpander ::$e_kind )), )* _ => return None , }}}; } macro_rules! __ra_macro_fixture345 {($($ty : ty =>$this : ident $im : block );*)=>{$(impl ToTokenTree for $ty { fn to_token ($this )-> tt :: TokenTree { let leaf : tt :: Leaf = $im . into (); leaf . into ()}} impl ToTokenTree for &$ty { fn to_token ($this )-> tt :: TokenTree { let leaf : tt :: Leaf = $im . clone (). into (); leaf . into ()}})* }} macro_rules! __ra_macro_fixture346 {($name : ident )=>{ impl $crate :: salsa :: InternKey for $name { fn from_intern_id ( v : $crate :: salsa :: InternId )-> Self {$name ( v )} fn as_intern_id (& self )-> $crate :: salsa :: InternId { self . 0 }}}; } macro_rules! __ra_macro_fixture347 {($($var : ident ($t : ty )),+ )=>{$(impl From <$t > for AttrOwner { fn from ( t : $t )-> AttrOwner { AttrOwner ::$var ( t )}})+ }; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs index 9bc1c54a3c6..b336f59ffee 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs @@ -40,6 +40,7 @@ pub struct StructData { pub repr: Option<ReprOptions>, pub visibility: RawVisibility, pub rustc_has_incoherent_inherent_impls: bool, + pub fundamental: bool, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -173,10 +174,10 @@ impl StructData { let item_tree = loc.id.item_tree(db); let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) - .by_key("rustc_has_incoherent_inherent_impls") - .exists(); + let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let rustc_has_incoherent_inherent_impls = + attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); + let fundamental = attrs.by_key("fundamental").exists(); let strukt = &item_tree[loc.id.value]; let (variant_data, diagnostics) = lower_fields( @@ -196,6 +197,7 @@ impl StructData { repr, visibility: item_tree[strukt.visibility].clone(), rustc_has_incoherent_inherent_impls, + fundamental, }), diagnostics.into(), ) @@ -215,10 +217,10 @@ impl StructData { let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) - .by_key("rustc_has_incoherent_inherent_impls") - .exists(); + let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let rustc_has_incoherent_inherent_impls = + attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); + let fundamental = attrs.by_key("fundamental").exists(); let union = &item_tree[loc.id.value]; let (variant_data, diagnostics) = lower_fields( @@ -238,6 +240,7 @@ impl StructData { repr, visibility: item_tree[union.visibility].clone(), rustc_has_incoherent_inherent_impls, + fundamental, }), diagnostics.into(), ) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 3be477d4877..b70e658efd7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -24,7 +24,9 @@ use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr}; use crate::{ attr::Attrs, db::DefDatabase, - expr::{dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId}, + expr::{ + dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat, + }, item_scope::BuiltinShadowMode, macro_id_to_def_id, nameres::DefMap, @@ -432,6 +434,44 @@ impl Body { pats.shrink_to_fit(); bindings.shrink_to_fit(); } + + pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) { + self.walk_pats(pat_id, &mut |pat| { + if let Pat::Bind { id, .. } = pat { + f(*id); + } + }); + } + + pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(&Pat)) { + let pat = &self[pat_id]; + f(pat); + match pat { + Pat::Range { .. } + | Pat::Lit(..) + | Pat::Path(..) + | Pat::ConstBlock(..) + | Pat::Wild + | Pat::Missing => {} + &Pat::Bind { subpat, .. } => { + if let Some(subpat) = subpat { + self.walk_pats(subpat, f); + } + } + Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { + args.iter().copied().for_each(|p| self.walk_pats(p, f)); + } + Pat::Ref { pat, .. } => self.walk_pats(*pat, f), + Pat::Slice { prefix, slice, suffix } => { + let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); + total_iter.copied().for_each(|p| self.walk_pats(p, f)); + } + Pat::Record { args, .. } => { + args.iter().for_each(|RecordFieldPat { pat, .. }| self.walk_pats(*pat, f)); + } + Pat::Box { inner } => self.walk_pats(*inner, f), + } + } } impl Default for Body { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 83ce9b6acbb..fedaf395598 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -499,6 +499,8 @@ impl ExprCollector<'_> { Movability::Movable }; ClosureKind::Generator(movability) + } else if e.async_token().is_some() { + ClosureKind::Async } else { ClosureKind::Closure }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index f8b159797e4..5a9b825a253 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -360,8 +360,14 @@ impl<'a> Printer<'a> { w!(self, "]"); } Expr::Closure { args, arg_types, ret_type, body, closure_kind } => { - if let ClosureKind::Generator(Movability::Static) = closure_kind { - w!(self, "static "); + match closure_kind { + ClosureKind::Generator(Movability::Static) => { + w!(self, "static "); + } + ClosureKind::Async => { + w!(self, "async "); + } + _ => (), } w!(self, "|"); for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index ee6e269fe55..1633a33bedd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -35,6 +35,7 @@ pub struct FunctionData { pub visibility: RawVisibility, pub abi: Option<Interned<str>>, pub legacy_const_generics_indices: Box<[u32]>, + pub rustc_allow_incoherent_impl: bool, flags: FnFlags, } @@ -84,13 +85,14 @@ impl FunctionData { } } - let legacy_const_generics_indices = item_tree - .attrs(db, krate, ModItem::from(loc.id.value).into()) + let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); + let legacy_const_generics_indices = attrs .by_key("rustc_legacy_const_generics") .tt_values() .next() .map(parse_rustc_legacy_const_generics) .unwrap_or_default(); + let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists(); Arc::new(FunctionData { name: func.name.clone(), @@ -108,6 +110,7 @@ impl FunctionData { abi: func.abi.clone(), legacy_const_generics_indices, flags, + rustc_allow_incoherent_impl, }) } @@ -171,6 +174,7 @@ pub struct TypeAliasData { pub visibility: RawVisibility, pub is_extern: bool, pub rustc_has_incoherent_inherent_impls: bool, + pub rustc_allow_incoherent_impl: bool, /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). pub bounds: Vec<Interned<TypeBound>>, } @@ -189,10 +193,14 @@ impl TypeAliasData { item_tree[typ.visibility].clone() }; - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into()) - .by_key("rustc_has_incoherent_inherent_impls") - .exists(); + let attrs = item_tree.attrs( + db, + loc.container.module(db).krate(), + ModItem::from(loc.id.value).into(), + ); + let rustc_has_incoherent_inherent_impls = + attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); + let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists(); Arc::new(TypeAliasData { name: typ.name.clone(), @@ -200,6 +208,7 @@ impl TypeAliasData { visibility, is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), rustc_has_incoherent_inherent_impls, + rustc_allow_incoherent_impl, bounds: typ.bounds.to_vec(), }) } @@ -212,11 +221,12 @@ pub struct TraitData { pub is_auto: bool, pub is_unsafe: bool, pub rustc_has_incoherent_inherent_impls: bool, + pub skip_array_during_method_dispatch: bool, + pub fundamental: bool, pub visibility: RawVisibility, /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore /// method calls to this trait's methods when the receiver is an array and the crate edition is /// 2015 or 2018. - pub skip_array_during_method_dispatch: bool, // box it as the vec is usually empty anyways pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, } @@ -245,6 +255,7 @@ impl TraitData { attrs.by_key("rustc_skip_array_during_method_dispatch").exists(); let rustc_has_incoherent_inherent_impls = attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); + let fundamental = attrs.by_key("fundamental").exists(); let mut collector = AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); @@ -260,6 +271,7 @@ impl TraitData { visibility, skip_array_during_method_dispatch, rustc_has_incoherent_inherent_impls, + fundamental, }), diagnostics.into(), ) @@ -450,6 +462,7 @@ pub struct ConstData { pub name: Option<Name>, pub type_ref: Interned<TypeRef>, pub visibility: RawVisibility, + pub rustc_allow_incoherent_impl: bool, } impl ConstData { @@ -463,10 +476,16 @@ impl ConstData { item_tree[konst.visibility].clone() }; + let rustc_allow_incoherent_impl = item_tree + .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into()) + .by_key("rustc_allow_incoherent_impl") + .exists(); + Arc::new(ConstData { name: konst.name.clone(), type_ref: konst.type_ref.clone(), visibility, + rustc_allow_incoherent_impl, }) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 270cfa06e58..9371fc14dd8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use base_db::{salsa, CrateId, SourceDatabase, Upcast}; use either::Either; -use hir_expand::{db::AstDatabase, HirFileId}; +use hir_expand::{db::ExpandDatabase, HirFileId}; use intern::Interned; use la_arena::ArenaMap; use syntax::{ast, AstPtr}; @@ -64,7 +64,7 @@ pub trait InternDatabase: SourceDatabase { } #[salsa::query_group(DefDatabaseStorage)] -pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { +pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDatabase> { #[salsa::input] fn enable_proc_attr_macros(&self) -> bool; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs index bbea608c55e..19fa6b25419 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs @@ -245,6 +245,7 @@ pub enum Expr { pub enum ClosureKind { Closure, Generator(Movability), + Async, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs index 5ab90d92d9b..314bf22b95e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs @@ -20,7 +20,7 @@ use ::mbe::TokenMap; use base_db::{fixture::WithFixture, ProcMacro, SourceDatabase}; use expect_test::Expect; use hir_expand::{ - db::{AstDatabase, TokenExpander}, + db::{ExpandDatabase, TokenExpander}, AstId, InFile, MacroDefId, MacroDefKind, MacroFile, }; use stdx::format_to; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 7d7240e7e8c..4efe8c58a69 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -120,6 +120,8 @@ pub struct DefMap { registered_tools: Vec<SmolStr>, /// Unstable features of Rust enabled with `#![feature(A, B)]`. unstable_features: FxHashSet<SmolStr>, + /// #[rustc_coherence_is_core] + rustc_coherence_is_core: bool, edition: Edition, recursion_limit: Option<u32>, @@ -215,7 +217,7 @@ pub struct ModuleData { pub origin: ModuleOrigin, /// Declared visibility of this module. pub visibility: Visibility, - + /// Always [`None`] for block modules pub parent: Option<LocalModuleId>, pub children: FxHashMap<Name, LocalModuleId>, pub scope: ItemScope, @@ -292,6 +294,7 @@ impl DefMap { registered_tools: Vec::new(), unstable_features: FxHashSet::default(), diagnostics: Vec::new(), + rustc_coherence_is_core: false, } } @@ -325,6 +328,10 @@ impl DefMap { self.unstable_features.contains(feature) } + pub fn is_rustc_coherence_is_core(&self) -> bool { + self.rustc_coherence_is_core + } + pub fn root(&self) -> LocalModuleId { self.root } @@ -337,7 +344,7 @@ impl DefMap { self.proc_macro_loading_error.as_deref() } - pub(crate) fn krate(&self) -> CrateId { + pub fn krate(&self) -> CrateId { self.krate } @@ -425,7 +432,7 @@ impl DefMap { Some(self.block?.parent) } - /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing + /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing /// the block, if `self` corresponds to a block expression. pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> { match self[local_mod].parent { @@ -498,6 +505,7 @@ impl DefMap { krate: _, prelude: _, root: _, + rustc_coherence_is_core: _, } = self; extern_prelude.shrink_to_fit(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 70acc3442c3..ddcee77ec4c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -87,10 +87,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T // FIXME: a hacky way to create a Name from string. let name = tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() }; - ( - name.as_name(), - ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)), - ) + (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32))) }) .collect() } @@ -299,6 +296,11 @@ impl DefCollector<'_> { continue; } + if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") { + self.def_map.rustc_coherence_is_core = true; + continue; + } + if *attr_name == hir_expand::name![feature] { let features = attr.parse_path_comma_token_tree().into_iter().flatten().filter_map( @@ -581,7 +583,7 @@ impl DefCollector<'_> { let kind = def.kind.to_basedb_kind(); let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { Some(&(_, expander)) => (expander, kind), - None => (ProcMacroExpander::dummy(self.def_map.krate), kind), + None => (ProcMacroExpander::dummy(), kind), }; let proc_macro_id = diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index b7908bddaa1..ee143b19ae5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -9,7 +9,7 @@ use base_db::{ salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, SourceDatabase, Upcast, }; -use hir_expand::{db::AstDatabase, InFile}; +use hir_expand::{db::ExpandDatabase, InFile}; use stdx::hash::NoHashHashSet; use syntax::{algo, ast, AstNode}; @@ -23,7 +23,7 @@ use crate::{ #[salsa::database( base_db::SourceDatabaseExtStorage, base_db::SourceDatabaseStorage, - hir_expand::db::AstDatabaseStorage, + hir_expand::db::ExpandDatabaseStorage, crate::db::InternDatabaseStorage, crate::db::DefDatabaseStorage )] @@ -40,8 +40,8 @@ impl Default for TestDB { } } -impl Upcast<dyn AstDatabase> for TestDB { - fn upcast(&self) -> &(dyn AstDatabase + 'static) { +impl Upcast<dyn ExpandDatabase> for TestDB { + fn upcast(&self) -> &(dyn ExpandDatabase + 'static) { &*self } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index c9fcaae56cf..ab76ed43d3a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -131,21 +131,23 @@ impl Visibility { // visibility as the containing module (even though no items are directly nameable from // there, getting this right is important for method resolution). // In that case, we adjust the visibility of `to_module` to point to the containing module. + // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're // currently computing, so we must not call the `def_map` query for it. - let arc; - let to_module_def_map = - if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() { - cov_mark::hit!(is_visible_from_same_block_def_map); - def_map - } else { - arc = to_module.def_map(db); - &arc - }; - let is_block_root = - to_module.block.is_some() && to_module_def_map[to_module.local_id].parent.is_none(); - if is_block_root { - to_module = to_module_def_map.containing_module(to_module.local_id).unwrap(); + let mut arc; + loop { + let to_module_def_map = + if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() { + cov_mark::hit!(is_visible_from_same_block_def_map); + def_map + } else { + arc = to_module.def_map(db); + &arc + }; + match to_module_def_map.parent() { + Some(parent) => to_module = parent, + None => break, + } } // from_module needs to be a descendant of to_module diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 5c04f8e8b8f..8d1e88725ec 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -10,7 +10,7 @@ use smallvec::{smallvec, SmallVec}; use syntax::{ast, match_ast, AstNode, SmolStr, SyntaxNode}; use crate::{ - db::AstDatabase, + db::ExpandDatabase, hygiene::Hygiene, mod_path::{ModPath, PathKind}, name::AsName, @@ -38,7 +38,7 @@ impl ops::Deref for RawAttrs { impl RawAttrs { pub const EMPTY: Self = Self { entries: None }; - pub fn new(db: &dyn AstDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self { + pub fn new(db: &dyn ExpandDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self { let entries = collect_attrs(owner) .filter_map(|(id, attr)| match attr { Either::Left(attr) => { @@ -55,7 +55,7 @@ impl RawAttrs { Self { entries: if entries.is_empty() { None } else { Some(entries) } } } - pub fn from_attrs_owner(db: &dyn AstDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self { + pub fn from_attrs_owner(db: &dyn ExpandDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self { let hygiene = Hygiene::new(db, owner.file_id); Self::new(db, owner.value, &hygiene) } @@ -87,7 +87,7 @@ impl RawAttrs { /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. // FIXME: This should return a different type - pub fn filter(self, db: &dyn AstDatabase, krate: CrateId) -> RawAttrs { + pub fn filter(self, db: &dyn ExpandDatabase, krate: CrateId) -> RawAttrs { let has_cfg_attrs = self .iter() .any(|attr| attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr])); @@ -199,7 +199,7 @@ impl fmt::Display for AttrInput { impl Attr { fn from_src( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, ast: ast::Meta, hygiene: &Hygiene, id: AttrId, @@ -221,7 +221,7 @@ impl Attr { } fn from_tt( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, tt: &tt::Subtree, hygiene: &Hygiene, id: AttrId, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs index 906ca991d73..277ecd93994 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs @@ -1,6 +1,6 @@ //! Builtin attributes. -use crate::{db::AstDatabase, name, tt, ExpandResult, MacroCallId, MacroCallKind}; +use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallId, MacroCallKind}; macro_rules! register_builtin { ( $(($name:ident, $variant:ident) => $expand:ident),* ) => { @@ -12,7 +12,7 @@ macro_rules! register_builtin { impl BuiltinAttrExpander { pub fn expand( &self, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -60,7 +60,7 @@ pub fn find_builtin_attr(ident: &name::Name) -> Option<BuiltinAttrExpander> { } fn dummy_attr_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -90,7 +90,7 @@ fn dummy_attr_expand( /// So this hacky approach is a lot more friendly for us, though it does require a bit of support in /// [`hir::Semantics`] to make this work. fn derive_attr_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs index 060a680542f..5c1a75132ee 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs @@ -9,7 +9,7 @@ use syntax::{ match_ast, }; -use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId}; +use crate::{db::ExpandDatabase, name, quote, ExpandError, ExpandResult, MacroCallId}; macro_rules! register_builtin { ( $($trait:ident => $expand:ident),* ) => { @@ -21,7 +21,7 @@ macro_rules! register_builtin { impl BuiltinDeriveExpander { pub fn expand( &self, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -141,7 +141,7 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu ExpandResult::ok(expanded) } -fn find_builtin_crate(db: &dyn AstDatabase, id: MacroCallId) -> tt::TokenTree { +fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId) -> tt::TokenTree { // FIXME: make hygiene works for builtin derive macro // such that $crate can be used here. let cg = db.crate_graph(); @@ -158,7 +158,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: MacroCallId) -> tt::TokenTree { } fn copy_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -167,7 +167,7 @@ fn copy_expand( } fn clone_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -176,7 +176,7 @@ fn clone_expand( } fn default_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -185,7 +185,7 @@ fn default_expand( } fn debug_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -194,7 +194,7 @@ fn debug_expand( } fn hash_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -202,13 +202,17 @@ fn hash_expand( expand_simple_derive(tt, quote! { #krate::hash::Hash }) } -fn eq_expand(db: &dyn AstDatabase, id: MacroCallId, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> { +fn eq_expand( + db: &dyn ExpandDatabase, + id: MacroCallId, + tt: &tt::Subtree, +) -> ExpandResult<tt::Subtree> { let krate = find_builtin_crate(db, id); expand_simple_derive(tt, quote! { #krate::cmp::Eq }) } fn partial_eq_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -217,7 +221,7 @@ fn partial_eq_expand( } fn ord_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -226,7 +230,7 @@ fn ord_expand( } fn partial_ord_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 295083a37f2..44510f2b7ff 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -10,7 +10,7 @@ use syntax::{ }; use crate::{ - db::AstDatabase, name, quote, tt, ExpandError, ExpandResult, MacroCallId, MacroCallLoc, + db::ExpandDatabase, name, quote, tt, ExpandError, ExpandResult, MacroCallId, MacroCallLoc, }; macro_rules! register_builtin { @@ -28,7 +28,7 @@ macro_rules! register_builtin { impl BuiltinFnLikeExpander { pub fn expand( &self, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -42,7 +42,7 @@ macro_rules! register_builtin { impl EagerExpander { pub fn expand( &self, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -121,7 +121,7 @@ const DOLLAR_CRATE: tt::Ident = tt::Ident { text: SmolStr::new_inline("$crate"), span: tt::TokenId::unspecified() }; fn module_path_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, _tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -130,7 +130,7 @@ fn module_path_expand( } fn line_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, _tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -144,7 +144,7 @@ fn line_expand( } fn log_syntax_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, _tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -152,7 +152,7 @@ fn log_syntax_expand( } fn trace_macros_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, _tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -160,7 +160,7 @@ fn trace_macros_expand( } fn stringify_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -174,7 +174,7 @@ fn stringify_expand( } fn column_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, _tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -188,7 +188,7 @@ fn column_expand( } fn assert_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -218,7 +218,7 @@ fn assert_expand( } fn file_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, _tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -234,7 +234,7 @@ fn file_expand( } fn format_args_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -276,7 +276,7 @@ fn format_args_expand( } fn asm_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -304,7 +304,7 @@ fn asm_expand( } fn global_asm_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, _tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -313,7 +313,7 @@ fn global_asm_expand( } fn cfg_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -325,7 +325,7 @@ fn cfg_expand( } fn panic_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -343,7 +343,7 @@ fn panic_expand( } fn unreachable_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -379,7 +379,7 @@ fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> { } fn compile_error_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -395,7 +395,7 @@ fn compile_error_expand( } fn concat_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -441,7 +441,7 @@ fn concat_expand( } fn concat_bytes_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -507,7 +507,7 @@ fn concat_bytes_expand_subtree( } fn concat_idents_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -529,7 +529,7 @@ fn concat_idents_expand( } fn relative_file( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, call_id: MacroCallId, path_str: &str, allow_recursion: bool, @@ -558,7 +558,7 @@ fn parse_string(tt: &tt::Subtree) -> Result<String, ExpandError> { } fn include_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -583,7 +583,7 @@ fn include_expand( } fn include_bytes_expand( - _db: &dyn AstDatabase, + _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -606,7 +606,7 @@ fn include_bytes_expand( } fn include_str_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -637,13 +637,13 @@ fn include_str_expand( ExpandResult::ok(ExpandedEager::new(quote!(#text))) } -fn get_env_inner(db: &dyn AstDatabase, arg_id: MacroCallId, key: &str) -> Option<String> { +fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &str) -> Option<String> { let krate = db.lookup_intern_macro_call(arg_id).krate; db.crate_graph()[krate].env.get(key) } fn env_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { @@ -679,7 +679,7 @@ fn env_expand( } fn option_env_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<ExpandedEager> { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 76016274f0e..45572499e84 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -44,7 +44,7 @@ pub enum TokenExpander { impl TokenExpander { fn expand( &self, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult<tt::Subtree> { @@ -83,9 +83,8 @@ impl TokenExpander { } } -// FIXME: rename to ExpandDatabase -#[salsa::query_group(AstDatabaseStorage)] -pub trait AstDatabase: SourceDatabase { +#[salsa::query_group(ExpandDatabaseStorage)] +pub trait ExpandDatabase: SourceDatabase { fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>; /// Main public API -- parses a hir file, not caring whether it's a real @@ -138,7 +137,7 @@ pub trait AstDatabase: SourceDatabase { /// token. The `token_to_map` mapped down into the expansion, with the mapped /// token returned. pub fn expand_speculative( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, actual_macro_call: MacroCallId, speculative_args: &SyntaxNode, token_to_map: SyntaxToken, @@ -211,7 +210,7 @@ pub fn expand_speculative( let mut speculative_expansion = match loc.def.kind { MacroDefKind::ProcMacro(expander, ..) => { tt.delimiter = tt::Delimiter::unspecified(); - expander.expand(db, loc.krate, &tt, attr_arg.as_ref()) + expander.expand(db, loc.def.krate, loc.krate, &tt, attr_arg.as_ref()) } MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => { pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?) @@ -236,12 +235,12 @@ pub fn expand_speculative( Some((node.syntax_node(), token)) } -fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { +fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> Arc<AstIdMap> { let map = db.parse_or_expand(file_id).map(|it| AstIdMap::from_source(&it)).unwrap_or_default(); Arc::new(map) } -fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { +fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> Option<SyntaxNode> { match file_id.repr() { HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), HirFileIdRepr::MacroFile(macro_file) => { @@ -253,13 +252,13 @@ fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNod } fn parse_macro_expansion( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, macro_file: MacroFile, ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> { let _p = profile::span("parse_macro_expansion"); - let result = db.macro_expand(macro_file.macro_call_id); + let mbe::ValueResult { value, err } = db.macro_expand(macro_file.macro_call_id); - if let Some(err) = &result.err { + if let Some(err) = &err { // Note: // The final goal we would like to make all parse_macro success, // such that the following log will not call anyway. @@ -280,9 +279,9 @@ fn parse_macro_expansion( parents ); } - let tt = match result.value { + let tt = match value { Some(tt) => tt, - None => return ExpandResult { value: None, err: result.err }, + None => return ExpandResult { value: None, err }, }; let expand_to = macro_expand_to(db, macro_file.macro_call_id); @@ -292,11 +291,11 @@ fn parse_macro_expansion( let (parse, rev_token_map) = token_tree_to_syntax_node(&tt, expand_to); - ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: result.err } + ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err } } fn macro_arg( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, id: MacroCallId, ) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>> { let arg = db.macro_arg_text(id)?; @@ -357,7 +356,7 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<Sy .unwrap_or_default() } -fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { +fn macro_arg_text(db: &dyn ExpandDatabase, id: MacroCallId) -> Option<GreenNode> { let loc = db.lookup_intern_macro_call(id); let arg = loc.kind.arg(db)?; if matches!(loc.kind, MacroCallKind::FnLike { .. }) { @@ -380,7 +379,10 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { Some(arg.green().into()) } -fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError> { +fn macro_def( + db: &dyn ExpandDatabase, + id: MacroDefId, +) -> Result<Arc<TokenExpander>, mbe::ParseError> { match id.kind { MacroDefKind::Declarative(ast_id) => { let (mac, def_site_token_map) = match ast_id.to_node(db) { @@ -419,7 +421,10 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result<Arc<TokenExpander>, } } -fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> { +fn macro_expand( + db: &dyn ExpandDatabase, + id: MacroCallId, +) -> ExpandResult<Option<Arc<tt::Subtree>>> { let _p = profile::span("macro_expand"); let loc: MacroCallLoc = db.lookup_intern_macro_call(id); if let Some(eager) = &loc.eager { @@ -469,11 +474,11 @@ fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Ar ExpandResult { value: Some(Arc::new(tt)), err } } -fn macro_expand_error(db: &dyn AstDatabase, macro_call: MacroCallId) -> Option<ExpandError> { +fn macro_expand_error(db: &dyn ExpandDatabase, macro_call: MacroCallId) -> Option<ExpandError> { db.macro_expand(macro_call).err } -fn expand_proc_macro(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<tt::Subtree> { +fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<tt::Subtree> { let loc: MacroCallLoc = db.lookup_intern_macro_call(id); let macro_arg = match db.macro_arg(id) { Some(it) => it, @@ -499,14 +504,14 @@ fn expand_proc_macro(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<tt:: _ => None, }; - expander.expand(db, loc.krate, ¯o_arg.0, attr_arg.as_ref()) + expander.expand(db, loc.def.krate, loc.krate, ¯o_arg.0, attr_arg.as_ref()) } -fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { +fn hygiene_frame(db: &dyn ExpandDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { Arc::new(HygieneFrame::new(db, file_id)) } -fn macro_expand_to(db: &dyn AstDatabase, id: MacroCallId) -> ExpandTo { +fn macro_expand_to(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandTo { let loc: MacroCallLoc = db.lookup_intern_macro_call(id); loc.kind.expand_to() } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index dfab7ec92c7..aca41b11f92 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -25,7 +25,7 @@ use syntax::{ted, SyntaxNode}; use crate::{ ast::{self, AstNode}, - db::AstDatabase, + db::ExpandDatabase, hygiene::Hygiene, mod_path::ModPath, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, InFile, MacroCallId, MacroCallKind, @@ -96,7 +96,7 @@ impl ErrorSink for &'_ mut dyn FnMut(ExpandError) { } pub fn expand_eager_macro( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, krate: CrateId, macro_call: InFile<ast::MacroCall>, def: MacroDefId, @@ -172,7 +172,7 @@ fn to_subtree(node: &SyntaxNode) -> crate::tt::Subtree { } fn lazy_expand( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, def: &MacroDefId, macro_call: InFile<ast::MacroCall>, krate: CrateId, @@ -193,7 +193,7 @@ fn lazy_expand( } fn eager_macro_recur( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, hygiene: &Hygiene, curr: InFile<SyntaxNode>, krate: CrateId, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index c811d1c66a8..b273f21768c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -636,9 +636,8 @@ fn foo() { if {} } "#, - // the {} gets parsed as the condition, I think? expect![[r#" -fn foo () {if {} {}} +fn foo () {if __ra_fixup {} {}} "#]], ) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index 2300ee9d089..2eb56fc9e8b 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -14,7 +14,7 @@ use syntax::{ }; use crate::{ - db::{self, AstDatabase}, + db::{self, ExpandDatabase}, fixup, name::{AsName, Name}, HirFileId, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile, @@ -26,7 +26,7 @@ pub struct Hygiene { } impl Hygiene { - pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { + pub fn new(db: &dyn ExpandDatabase, file_id: HirFileId) -> Hygiene { Hygiene { frames: Some(HygieneFrames::new(db, file_id)) } } @@ -37,7 +37,7 @@ impl Hygiene { // FIXME: this should just return name pub fn name_ref_to_name( &self, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, name_ref: ast::NameRef, ) -> Either<Name, CrateId> { if let Some(frames) = &self.frames { @@ -51,7 +51,7 @@ impl Hygiene { Either::Left(name_ref.as_name()) } - pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option<CrateId> { + pub fn local_inner_macros(&self, db: &dyn ExpandDatabase, path: ast::Path) -> Option<CrateId> { let mut token = path.syntax().first_token()?.text_range(); let frames = self.frames.as_ref()?; let mut current = &frames.0; @@ -87,13 +87,13 @@ pub struct HygieneFrame { } impl HygieneFrames { - fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { + fn new(db: &dyn ExpandDatabase, file_id: HirFileId) -> Self { // Note that this intentionally avoids the `hygiene_frame` query to avoid blowing up memory // usage. The query is only helpful for nested `HygieneFrame`s as it avoids redundant work. HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) } - fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option<CrateId> { + fn root_crate(&self, db: &dyn ExpandDatabase, node: &SyntaxNode) -> Option<CrateId> { let mut token = node.first_token()?.text_range(); let mut result = self.0.krate; let mut current = self.0.clone(); @@ -136,7 +136,7 @@ struct HygieneInfo { impl HygieneInfo { fn map_ident_up( &self, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, token: TextRange, ) -> Option<(InFile<TextRange>, Origin)> { let token_id = self.exp_map.token_by_range(token)?; @@ -175,7 +175,7 @@ impl HygieneInfo { } fn make_hygiene_info( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, macro_file: MacroFile, loc: &MacroCallLoc, ) -> Option<HygieneInfo> { @@ -215,7 +215,7 @@ fn make_hygiene_info( } impl HygieneFrame { - pub(crate) fn new(db: &dyn AstDatabase, file_id: HirFileId) -> HygieneFrame { + pub(crate) fn new(db: &dyn ExpandDatabase, file_id: HirFileId) -> HygieneFrame { let (info, krate, local_inner) = match file_id.macro_file() { None => (None, None, false), Some(macro_file) => { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 39fc08ecdcf..5e99eacc1b6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -198,7 +198,7 @@ impl HirFileId { /// For macro-expansion files, returns the file original source file the /// expansion originated from. - pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId { + pub fn original_file(self, db: &dyn db::ExpandDatabase) -> FileId { let mut file_id = self; loop { match file_id.repr() { @@ -214,7 +214,7 @@ impl HirFileId { } } - pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 { + pub fn expansion_level(self, db: &dyn db::ExpandDatabase) -> u32 { let mut level = 0; let mut curr = self; while let Some(macro_file) = curr.macro_file() { @@ -227,14 +227,14 @@ impl HirFileId { } /// If this is a macro call, returns the syntax node of the call. - pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { + pub fn call_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxNode>> { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); Some(loc.kind.to_node(db)) } /// If this is a macro call, returns the syntax node of the very first macro call this file resides in. - pub fn original_call_node(self, db: &dyn db::AstDatabase) -> Option<(FileId, SyntaxNode)> { + pub fn original_call_node(self, db: &dyn db::ExpandDatabase) -> Option<(FileId, SyntaxNode)> { let mut call = db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).kind.to_node(db); loop { @@ -248,7 +248,7 @@ impl HirFileId { } /// Return expansion information if it is a macro-expansion file - pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> { + pub fn expansion_info(self, db: &dyn db::ExpandDatabase) -> Option<ExpansionInfo> { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); @@ -294,7 +294,7 @@ impl HirFileId { } /// Indicate it is macro file generated for builtin derive - pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::Attr>> { + pub fn is_builtin_derive(&self, db: &dyn db::ExpandDatabase) -> Option<InFile<ast::Attr>> { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); let attr = match loc.def.kind { @@ -304,7 +304,7 @@ impl HirFileId { Some(attr.with_value(ast::Attr::cast(attr.value.clone())?)) } - pub fn is_custom_derive(&self, db: &dyn db::AstDatabase) -> bool { + pub fn is_custom_derive(&self, db: &dyn db::ExpandDatabase) -> bool { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); @@ -315,7 +315,7 @@ impl HirFileId { } /// Return whether this file is an include macro - pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool { + pub fn is_include_macro(&self, db: &dyn db::ExpandDatabase) -> bool { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); @@ -326,7 +326,7 @@ impl HirFileId { } /// Return whether this file is an attr macro - pub fn is_attr_macro(&self, db: &dyn db::AstDatabase) -> bool { + pub fn is_attr_macro(&self, db: &dyn db::ExpandDatabase) -> bool { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); @@ -338,7 +338,7 @@ impl HirFileId { /// Return whether this file is the pseudo expansion of the derive attribute. /// See [`crate::builtin_attr_macro::derive_attr_expand`]. - pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::AstDatabase) -> bool { + pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::ExpandDatabase) -> bool { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); @@ -384,7 +384,7 @@ impl HirFileId { impl MacroDefId { pub fn as_lazy_macro( self, - db: &dyn db::AstDatabase, + db: &dyn db::ExpandDatabase, krate: CrateId, kind: MacroCallKind, ) -> MacroCallId { @@ -427,7 +427,7 @@ impl MacroCallKind { } } - pub fn to_node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { + pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> InFile<SyntaxNode> { match self { MacroCallKind::FnLike { ast_id, .. } => { ast_id.with_value(ast_id.to_node(db).syntax().clone()) @@ -465,7 +465,7 @@ impl MacroCallKind { /// Returns the original file range that best describes the location of this macro call. /// /// Unlike `MacroCallKind::original_call_range`, this also spans the item of attributes and derives. - pub fn original_call_range_with_body(self, db: &dyn db::AstDatabase) -> FileRange { + pub fn original_call_range_with_body(self, db: &dyn db::ExpandDatabase) -> FileRange { let mut kind = self; let file_id = loop { match kind.file_id().repr() { @@ -490,7 +490,7 @@ impl MacroCallKind { /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives /// get only the specific derive that is being referred to. - pub fn original_call_range(self, db: &dyn db::AstDatabase) -> FileRange { + pub fn original_call_range(self, db: &dyn db::ExpandDatabase) -> FileRange { let mut kind = self; let file_id = loop { match kind.file_id().repr() { @@ -529,7 +529,7 @@ impl MacroCallKind { FileRange { range, file_id } } - fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { + fn arg(&self, db: &dyn db::ExpandDatabase) -> Option<SyntaxNode> { match self { MacroCallKind::FnLike { ast_id, .. } => { Some(ast_id.to_node(db).token_tree()?.syntax().clone()) @@ -597,7 +597,7 @@ impl ExpansionInfo { /// Both of these only have one simple call site input so no special handling is required here. pub fn map_token_down( &self, - db: &dyn db::AstDatabase, + db: &dyn db::ExpandDatabase, item: Option<ast::Item>, token: InFile<&SyntaxToken>, ) -> Option<impl Iterator<Item = InFile<SyntaxToken>> + '_> { @@ -666,7 +666,7 @@ impl ExpansionInfo { /// Map a token up out of the expansion it resides in into the arguments of the macro call of the expansion. pub fn map_token_up( &self, - db: &dyn db::AstDatabase, + db: &dyn db::ExpandDatabase, token: InFile<&SyntaxToken>, ) -> Option<(InFile<SyntaxToken>, Origin)> { // Fetch the id through its text range, @@ -717,7 +717,7 @@ impl ExpansionInfo { pub type AstId<N> = InFile<FileAstId<N>>; impl<N: AstNode> AstId<N> { - pub fn to_node(&self, db: &dyn db::AstDatabase) -> N { + pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> N { let root = db.parse_or_expand(self.file_id).unwrap(); db.ast_id_map(self.file_id).get(self.value).to_node(&root) } @@ -753,7 +753,7 @@ impl<T> InFile<T> { self.with_value(&self.value) } - pub fn file_syntax(&self, db: &dyn db::AstDatabase) -> SyntaxNode { + pub fn file_syntax(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode { db.parse_or_expand(self.file_id).expect("source created from invalid file") } } @@ -783,7 +783,7 @@ impl<L, R> InFile<Either<L, R>> { impl<'a> InFile<&'a SyntaxNode> { pub fn ancestors_with_macros( self, - db: &dyn db::AstDatabase, + db: &dyn db::ExpandDatabase, ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ { iter::successors(Some(self.cloned()), move |node| match node.value.parent() { Some(parent) => Some(node.with_value(parent)), @@ -794,7 +794,7 @@ impl<'a> InFile<&'a SyntaxNode> { /// Skips the attributed item that caused the macro invocation we are climbing up pub fn ancestors_with_macros_skip_attr_item( self, - db: &dyn db::AstDatabase, + db: &dyn db::ExpandDatabase, ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ { let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() { Some(parent) => Some(node.with_value(parent)), @@ -816,7 +816,7 @@ impl<'a> InFile<&'a SyntaxNode> { /// /// For attributes and derives, this will point back to the attribute only. /// For the entire item use [`InFile::original_file_range_full`]. - pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange { + pub fn original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange { match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() }, HirFileIdRepr::MacroFile(mac_file) => { @@ -831,7 +831,7 @@ impl<'a> InFile<&'a SyntaxNode> { } /// Falls back to the macro call range if the node cannot be mapped up fully. - pub fn original_file_range_full(self, db: &dyn db::AstDatabase) -> FileRange { + pub fn original_file_range_full(self, db: &dyn db::ExpandDatabase) -> FileRange { match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() }, HirFileIdRepr::MacroFile(mac_file) => { @@ -846,7 +846,7 @@ impl<'a> InFile<&'a SyntaxNode> { } /// Attempts to map the syntax node back up its macro calls. - pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> { + pub fn original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option<FileRange> { match ascend_node_border_tokens(db, self) { Some(InFile { file_id, value: (first, last) }) => { let original_file = file_id.original_file(db); @@ -865,7 +865,7 @@ impl<'a> InFile<&'a SyntaxNode> { } } - pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { + pub fn original_syntax_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxNode>> { // This kind of upmapping can only be achieved in attribute expanded files, // as we don't have node inputs otherwise and therefore can't find an `N` node in the input if !self.file_id.is_macro() { @@ -892,13 +892,13 @@ impl<'a> InFile<&'a SyntaxNode> { } impl InFile<SyntaxToken> { - pub fn upmap(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxToken>> { + pub fn upmap(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxToken>> { let expansion = self.file_id.expansion_info(db)?; expansion.map_token_up(db, self.as_ref()).map(|(it, _)| it) } /// Falls back to the macro call range if the node cannot be mapped up fully. - pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange { + pub fn original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange { match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() }, HirFileIdRepr::MacroFile(mac_file) => { @@ -913,7 +913,7 @@ impl InFile<SyntaxToken> { } /// Attempts to map the syntax node back up its macro calls. - pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> { + pub fn original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option<FileRange> { match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => { Some(FileRange { file_id, range: self.value.text_range() }) @@ -932,7 +932,7 @@ impl InFile<SyntaxToken> { pub fn ancestors_with_macros( self, - db: &dyn db::AstDatabase, + db: &dyn db::ExpandDatabase, ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ { self.value.parent().into_iter().flat_map({ let file_id = self.file_id; @@ -942,7 +942,7 @@ impl InFile<SyntaxToken> { } fn ascend_node_border_tokens( - db: &dyn db::AstDatabase, + db: &dyn db::ExpandDatabase, InFile { file_id, value: node }: InFile<&SyntaxNode>, ) -> Option<InFile<(SyntaxToken, SyntaxToken)>> { let expansion = file_id.expansion_info(db)?; @@ -958,7 +958,7 @@ fn ascend_node_border_tokens( } fn ascend_call_token( - db: &dyn db::AstDatabase, + db: &dyn db::ExpandDatabase, expansion: &ExpansionInfo, token: InFile<SyntaxToken>, ) -> Option<InFile<SyntaxToken>> { @@ -977,7 +977,7 @@ impl<N: AstNode> InFile<N> { self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n)) } - pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option<InFile<N>> { + pub fn original_ast_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<N>> { // This kind of upmapping can only be achieved in attribute expanded files, // as we don't have node inputs otherwise and therefore can't find an `N` node in the input if !self.file_id.is_macro() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index d7586d129b7..e9393cc89ae 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -6,7 +6,7 @@ use std::{ }; use crate::{ - db::AstDatabase, + db::ExpandDatabase, hygiene::Hygiene, name::{known, Name}, }; @@ -37,7 +37,11 @@ pub enum PathKind { } impl ModPath { - pub fn from_src(db: &dyn AstDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { + pub fn from_src( + db: &dyn ExpandDatabase, + path: ast::Path, + hygiene: &Hygiene, + ) -> Option<ModPath> { convert_path(db, None, path, hygiene) } @@ -162,7 +166,7 @@ impl From<Name> for ModPath { } fn convert_path( - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs index 3f4d2540c09..d758e9302cd 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs @@ -3,22 +3,20 @@ use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind}; use stdx::never; -use crate::{db::AstDatabase, tt, ExpandError, ExpandResult}; +use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct ProcMacroExpander { - krate: CrateId, proc_macro_id: Option<ProcMacroId>, } impl ProcMacroExpander { - pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> Self { - Self { krate, proc_macro_id: Some(proc_macro_id) } + pub fn new(proc_macro_id: ProcMacroId) -> Self { + Self { proc_macro_id: Some(proc_macro_id) } } - pub fn dummy(krate: CrateId) -> Self { - // FIXME: Should store the name for better errors - Self { krate, proc_macro_id: None } + pub fn dummy() -> Self { + Self { proc_macro_id: None } } pub fn is_dummy(&self) -> bool { @@ -27,7 +25,8 @@ impl ProcMacroExpander { pub fn expand( self, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, + def_crate: CrateId, calling_crate: CrateId, tt: &tt::Subtree, attr_arg: Option<&tt::Subtree>, @@ -35,7 +34,7 @@ impl ProcMacroExpander { match self.proc_macro_id { Some(id) => { let krate_graph = db.crate_graph(); - let proc_macros = match &krate_graph[self.krate].proc_macro { + let proc_macros = match &krate_graph[def_crate].proc_macro { Ok(proc_macros) => proc_macros, Err(_) => { never!("Non-dummy expander even though there are no proc macros"); @@ -84,7 +83,7 @@ impl ProcMacroExpander { } None => ExpandResult::with_err( tt::Subtree::empty(), - ExpandError::UnresolvedProcMacro(self.krate), + ExpandError::UnresolvedProcMacro(def_crate), ), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 4572e33486f..9b3296df250 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -22,10 +22,10 @@ either = "1.7.0" tracing = "0.1.35" rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.88.0", default-features = false } -chalk-ir = "0.88.0" -chalk-recursive = { version = "0.88.0", default-features = false } -chalk-derive = "0.88.0" +chalk-solve = { version = "0.89.0", default-features = false } +chalk-ir = "0.89.0" +chalk-recursive = { version = "0.89.0", default-features = false } +chalk-derive = "0.89.0" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } once_cell = "1.17.0" typed-arena = "2.0.1" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index e6aefbf2716..2141894922f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -12,7 +12,7 @@ use hir_def::{ use crate::{ db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, to_chalk_trait_id, utils::generics, AdtId, AliasEq, AliasTy, Binders, - CallableDefId, CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, + CallableDefId, CallableSig, DynTy, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause, }; @@ -378,6 +378,19 @@ impl ProjectionTyExt for ProjectionTy { } } +pub trait DynTyExt { + fn principal(&self) -> Option<&TraitRef>; +} + +impl DynTyExt for DynTy { + fn principal(&self) -> Option<&TraitRef> { + self.bounds.skip_binders().interned().get(0).and_then(|b| match b.skip_binders() { + crate::WhereClause::Implemented(trait_ref) => Some(trait_ref), + _ => None, + }) + } +} + pub trait TraitRefExt { fn hir_trait_id(&self) -> TraitId; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs index 37eb06be1d3..4b147b99707 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs @@ -11,3 +11,9 @@ pub use crate::diagnostics::{ }, unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr}, }; + +#[derive(Debug, PartialEq, Eq)] +pub struct IncoherentImpl { + pub file_id: hir_expand::HirFileId, + pub impl_: syntax::AstPtr<syntax::ast::Impl>, +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 535189ff028..ee186673ee1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -275,7 +275,23 @@ impl<'a> InferenceContext<'a> { Some(type_ref) => self.make_ty(type_ref), None => self.table.new_type_var(), }; - sig_tys.push(ret_ty.clone()); + if let ClosureKind::Async = closure_kind { + // Use the first type parameter as the output type of future. + // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType> + let impl_trait_id = + crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body); + let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); + sig_tys.push( + TyKind::OpaqueType( + opaque_ty_id, + Substitution::from1(Interner, ret_ty.clone()), + ) + .intern(Interner), + ); + } else { + sig_tys.push(ret_ty.clone()); + } + let sig_ty = TyKind::Function(FnPointer { num_binders: 0, sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false }, @@ -286,33 +302,38 @@ impl<'a> InferenceContext<'a> { }) .intern(Interner); - let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) { - // FIXME: report error when there are more than 1 parameter. - let resume_ty = match sig_tys.first() { - // When `sig_tys.len() == 1` the first type is the return type, not the - // first parameter type. - Some(ty) if sig_tys.len() > 1 => ty.clone(), - _ => self.result.standard_types.unit.clone(), - }; - let yield_ty = self.table.new_type_var(); - - let subst = TyBuilder::subst_for_generator(self.db, self.owner) - .push(resume_ty.clone()) - .push(yield_ty.clone()) - .push(ret_ty.clone()) - .build(); + let (ty, resume_yield_tys) = match closure_kind { + ClosureKind::Generator(_) => { + // FIXME: report error when there are more than 1 parameter. + let resume_ty = match sig_tys.first() { + // When `sig_tys.len() == 1` the first type is the return type, not the + // first parameter type. + Some(ty) if sig_tys.len() > 1 => ty.clone(), + _ => self.result.standard_types.unit.clone(), + }; + let yield_ty = self.table.new_type_var(); + + let subst = TyBuilder::subst_for_generator(self.db, self.owner) + .push(resume_ty.clone()) + .push(yield_ty.clone()) + .push(ret_ty.clone()) + .build(); - let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into(); - let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner); + let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into(); + let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner); - (generator_ty, Some((resume_ty, yield_ty))) - } else { - let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); - let closure_ty = - TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone())) - .intern(Interner); + (generator_ty, Some((resume_ty, yield_ty))) + } + ClosureKind::Closure | ClosureKind::Async => { + let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); + let closure_ty = TyKind::Closure( + closure_id, + Substitution::from1(Interner, sig_ty.clone()), + ) + .intern(Interner); - (closure_ty, None) + (closure_ty, None) + } }; // Eagerly try to relate the closure type with the expected @@ -321,7 +342,7 @@ impl<'a> InferenceContext<'a> { self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected); // Now go through the argument patterns - for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { + for (arg_pat, arg_ty) in args.iter().zip(&sig_tys) { self.infer_top_pat(*arg_pat, &arg_ty); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 0f49e837881..5f839fc307a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -5,10 +5,7 @@ use std::iter::repeat_with; use chalk_ir::Mutability; use hir_def::{ body::Body, - expr::{ - Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId, - RecordFieldPat, - }, + expr::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId}, path::Path, }; use hir_expand::name::Name; @@ -439,38 +436,8 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool { let mut res = false; - walk_pats(body, pat_id, &mut |pat| { + body.walk_pats(pat_id, &mut |pat| { res |= matches!(pat, Pat::Bind { id, .. } if body.bindings[*id].mode == BindingAnnotation::Ref); }); res } - -fn walk_pats(body: &Body, pat_id: PatId, f: &mut impl FnMut(&Pat)) { - let pat = &body[pat_id]; - f(pat); - match pat { - Pat::Range { .. } - | Pat::Lit(..) - | Pat::Path(..) - | Pat::ConstBlock(..) - | Pat::Wild - | Pat::Missing => {} - &Pat::Bind { subpat, .. } => { - if let Some(subpat) = subpat { - walk_pats(body, subpat, f); - } - } - Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { - args.iter().copied().for_each(|p| walk_pats(body, p, f)); - } - Pat::Ref { pat, .. } => walk_pats(body, *pat, f), - Pat::Slice { prefix, slice, suffix } => { - let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); - total_iter.copied().for_each(|p| walk_pats(body, p, f)); - } - Pat::Record { args, .. } => { - args.iter().for_each(|RecordFieldPat { pat, .. }| walk_pats(body, *pat, f)); - } - Pat::Box { inner } => walk_pats(body, *inner, f), - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 92a17fc3a99..f3a27632bf5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -19,13 +19,13 @@ use stdx::never; use crate::{ autoderef::{self, AutoderefKind}, db::HirDatabase, - from_foreign_def_id, + from_chalk_trait_id, from_foreign_def_id, infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast}, primitive::{FloatTy, IntTy, UintTy}, static_lifetime, to_chalk_trait_id, utils::all_super_traits, - AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner, - Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, + AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment, + Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, }; /// This is used as a key for indexing impls. @@ -266,11 +266,12 @@ impl TraitImpls { #[derive(Debug, Eq, PartialEq)] pub struct InherentImpls { map: FxHashMap<TyFingerprint, Vec<ImplId>>, + invalid_impls: Vec<ImplId>, } impl InherentImpls { pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { - let mut impls = Self { map: FxHashMap::default() }; + let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; let crate_def_map = db.crate_def_map(krate); impls.collect_def_map(db, &crate_def_map); @@ -283,7 +284,7 @@ impl InherentImpls { db: &dyn HirDatabase, block: BlockId, ) -> Option<Arc<Self>> { - let mut impls = Self { map: FxHashMap::default() }; + let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; if let Some(block_def_map) = db.block_def_map(block) { impls.collect_def_map(db, &block_def_map); impls.shrink_to_fit(); @@ -306,11 +307,17 @@ impl InherentImpls { } let self_ty = db.impl_self_ty(impl_id); - let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders()); - if let Some(fp) = fp { - self.map.entry(fp).or_default().push(impl_id); + let self_ty = self_ty.skip_binders(); + + match is_inherent_impl_coherent(db, def_map, &data, self_ty) { + true => { + // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) + if let Some(fp) = TyFingerprint::for_inherent_impl(self_ty) { + self.map.entry(fp).or_default().push(impl_id); + } + } + false => self.invalid_impls.push(impl_id), } - // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) } // To better support custom derives, collect impls in all unnamed const items. @@ -334,6 +341,10 @@ impl InherentImpls { pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ { self.map.values().flat_map(|v| v.iter().copied()) } + + pub fn invalid_impls(&self) -> &[ImplId] { + &self.invalid_impls + } } pub(crate) fn incoherent_inherent_impl_crates( @@ -775,6 +786,69 @@ fn find_matching_impl( } } +fn is_inherent_impl_coherent( + db: &dyn HirDatabase, + def_map: &DefMap, + impl_data: &ImplData, + self_ty: &Ty, +) -> bool { + let self_ty = self_ty.kind(Interner); + let impl_allowed = match self_ty { + TyKind::Tuple(_, _) + | TyKind::FnDef(_, _) + | TyKind::Array(_, _) + | TyKind::Never + | TyKind::Raw(_, _) + | TyKind::Ref(_, _, _) + | TyKind::Slice(_) + | TyKind::Str + | TyKind::Scalar(_) => def_map.is_rustc_coherence_is_core(), + + &TyKind::Adt(AdtId(adt), _) => adt.module(db.upcast()).krate() == def_map.krate(), + TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| { + from_chalk_trait_id(trait_ref.trait_id).module(db.upcast()).krate() == def_map.krate() + }), + + _ => true, + }; + impl_allowed || { + let rustc_has_incoherent_inherent_impls = match self_ty { + TyKind::Tuple(_, _) + | TyKind::FnDef(_, _) + | TyKind::Array(_, _) + | TyKind::Never + | TyKind::Raw(_, _) + | TyKind::Ref(_, _, _) + | TyKind::Slice(_) + | TyKind::Str + | TyKind::Scalar(_) => true, + + &TyKind::Adt(AdtId(adt), _) => match adt { + hir_def::AdtId::StructId(it) => { + db.struct_data(it).rustc_has_incoherent_inherent_impls + } + hir_def::AdtId::UnionId(it) => { + db.union_data(it).rustc_has_incoherent_inherent_impls + } + hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls, + }, + TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| { + db.trait_data(from_chalk_trait_id(trait_ref.trait_id)) + .rustc_has_incoherent_inherent_impls + }), + + _ => false, + }; + rustc_has_incoherent_inherent_impls + && !impl_data.items.is_empty() + && impl_data.items.iter().copied().all(|assoc| match assoc { + AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl, + AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl, + AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl, + }) + } +} + pub fn iterate_path_candidates( ty: &Canonical<Ty>, db: &dyn HirDatabase, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 435a914088b..c4dd7c0ace4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -1113,7 +1113,7 @@ impl MirLowerCtx<'_> { if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) { binding_mode = mode; } - self.push_storage_live(*id, current)?; + self.push_storage_live(*id, current); self.push_assignment( current, target_place.into(), @@ -1327,8 +1327,9 @@ impl MirLowerCtx<'_> { is_ty_uninhabited_from(&self.infer[expr_id], self.owner.module(self.db.upcast()), self.db) } - /// This function push `StorageLive` statements for each binding in the pattern. - fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<()> { + /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` in + /// the appropriated places. + fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) { // Current implementation is wrong. It adds no `StorageDead` at the end of scope, and before each break // and continue. It just add a `StorageDead` before the `StorageLive`, which is not wrong, but unneeeded in // the proper implementation. Due this limitation, implementing a borrow checker on top of this mir will falsely @@ -1356,7 +1357,6 @@ impl MirLowerCtx<'_> { let l = self.result.binding_locals[b]; self.push_statement(current, StatementKind::StorageDead(l).with_span(span)); self.push_statement(current, StatementKind::StorageLive(l).with_span(span)); - Ok(()) } fn resolve_lang_item(&self, item: LangItem) -> Result<LangItemTarget> { @@ -1381,10 +1381,10 @@ impl MirLowerCtx<'_> { if let Some(expr_id) = initializer { let else_block; let Some((init_place, c)) = - self.lower_expr_as_place(current, *expr_id, true)? - else { - return Ok(None); - }; + self.lower_expr_as_place(current, *expr_id, true)? + else { + return Ok(None); + }; current = c; (current, else_block) = self.pattern_match( current, @@ -1407,6 +1407,10 @@ impl MirLowerCtx<'_> { } } } + } else { + self.body.walk_bindings_in_pat(*pat, |b| { + self.push_storage_live(b, current); + }); } } hir_def::expr::Statement::Expr { expr, has_semi: _ } => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index 118e5311e9a..8c48331b94b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -9,7 +9,7 @@ use base_db::{ salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast, }; use hir_def::{db::DefDatabase, ModuleId}; -use hir_expand::db::AstDatabase; +use hir_expand::db::ExpandDatabase; use stdx::hash::{NoHashHashMap, NoHashHashSet}; use syntax::TextRange; use test_utils::extract_annotations; @@ -17,7 +17,7 @@ use test_utils::extract_annotations; #[salsa::database( base_db::SourceDatabaseExtStorage, base_db::SourceDatabaseStorage, - hir_expand::db::AstDatabaseStorage, + hir_expand::db::ExpandDatabaseStorage, hir_def::db::InternDatabaseStorage, hir_def::db::DefDatabaseStorage, crate::db::HirDatabaseStorage @@ -41,8 +41,8 @@ impl fmt::Debug for TestDB { } } -impl Upcast<dyn AstDatabase> for TestDB { - fn upcast(&self) -> &(dyn AstDatabase + 'static) { +impl Upcast<dyn ExpandDatabase> for TestDB { + fn upcast(&self) -> &(dyn ExpandDatabase + 'static) { &*self } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index bcd63d9472a..83d31f002a1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -23,7 +23,7 @@ use hir_def::{ src::HasSource, AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, }; -use hir_expand::{db::AstDatabase, InFile}; +use hir_expand::{db::ExpandDatabase, InFile}; use once_cell::race::OnceBool; use stdx::format_to; use syntax::{ diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index e568e7013fa..378d4783361 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -9,6 +9,7 @@ fn infer_slice_method() { check_types( r#" impl<T> [T] { + #[rustc_allow_incoherent_impl] fn foo(&self) -> T { loop {} } @@ -35,6 +36,7 @@ fn test() { //- /lib.rs crate:other_crate mod foo { impl f32 { + #[rustc_allow_incoherent_impl] pub fn foo(self) -> f32 { 0. } } } @@ -47,6 +49,7 @@ fn infer_array_inherent_impl() { check_types( r#" impl<T, const N: usize> [T; N] { + #[rustc_allow_incoherent_impl] fn foo(&self) -> T { loop {} } @@ -1437,6 +1440,7 @@ fn resolve_const_generic_array_methods() { r#" #[lang = "array"] impl<T, const N: usize> [T; N] { + #[rustc_allow_incoherent_impl] pub fn map<F, U>(self, f: F) -> [U; N] where F: FnMut(T) -> U, @@ -1445,6 +1449,7 @@ impl<T, const N: usize> [T; N] { #[lang = "slice"] impl<T> [T] { + #[rustc_allow_incoherent_impl] pub fn map<F, U>(self, f: F) -> &[U] where F: FnMut(T) -> U, @@ -1468,6 +1473,7 @@ struct Const<const N: usize>; #[lang = "array"] impl<T, const N: usize> [T; N] { + #[rustc_allow_incoherent_impl] pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X] where F: FnMut(T) -> U, @@ -1476,6 +1482,7 @@ impl<T, const N: usize> [T; N] { #[lang = "slice"] impl<T> [T] { + #[rustc_allow_incoherent_impl] pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U] where F: FnMut(T) -> U, @@ -1874,14 +1881,14 @@ fn incoherent_impls() { pub struct Box<T>(T); use core::error::Error; -#[rustc_allow_incoherent_impl] impl dyn Error { + #[rustc_allow_incoherent_impl] pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> { loop {} } } -#[rustc_allow_incoherent_impl] impl dyn Error + Send { + #[rustc_allow_incoherent_impl] /// Attempts to downcast the box to a concrete type. pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> { let err: Box<dyn Error> = self; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index e6b4f13c8d1..689f0da44f6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -1756,3 +1756,35 @@ const C: usize = 2 + 2; "#, ); } + +#[test] +fn regression_14164() { + check_types( + r#" +trait Rec { + type K; + type Rebind<Tok>: Rec<K = Tok>; +} + +trait Expr<K> { + type Part: Rec<K = K>; + fn foo(_: <Self::Part as Rec>::Rebind<i32>) {} +} + +struct Head<K>(K); +impl<K> Rec for Head<K> { + type K = K; + type Rebind<Tok> = Head<Tok>; +} + +fn test<E>() +where + E: Expr<usize, Part = Head<usize>>, +{ + let head; + //^^^^ Head<i32> + E::foo(head); +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 0e9c349afef..13cc3fea52d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -1116,21 +1116,22 @@ fn infer_inherent_method() { fn infer_inherent_method_str() { check_infer( r#" - #[lang = "str"] - impl str { - fn foo(&self) -> i32 {} - } +#![rustc_coherence_is_core] +#[lang = "str"] +impl str { + fn foo(&self) -> i32 {} +} - fn test() { - "foo".foo(); - } - "#, +fn test() { + "foo".foo(); +} +"#, expect![[r#" - 39..43 'self': &str - 52..54 '{}': i32 - 68..88 '{ ...o(); }': () - 74..79 '"foo"': &str - 74..85 '"foo".foo()': i32 + 67..71 'self': &str + 80..82 '{}': i32 + 96..116 '{ ...o(); }': () + 102..107 '"foo"': &str + 102..113 '"foo".foo()': i32 "#]], ); } @@ -2640,6 +2641,7 @@ impl<T> [T] {} #[lang = "slice_alloc"] impl<T> [T] { + #[rustc_allow_incoherent_impl] pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> { unimplemented!() } @@ -2655,22 +2657,22 @@ struct Astruct; impl B for Astruct {} "#, expect![[r#" - 569..573 'self': Box<[T], A> - 602..634 '{ ... }': Vec<T, A> - 648..761 '{ ...t]); }': () - 658..661 'vec': Vec<i32, Global> - 664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global> - 664..691 '<[_]>:...1i32])': Vec<i32, Global> - 680..690 'box [1i32]': Box<[i32; 1], Global> - 684..690 '[1i32]': [i32; 1] - 685..689 '1i32': i32 - 701..702 'v': Vec<Box<dyn B, Global>, Global> - 722..739 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global> - 722..758 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global> - 740..757 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global> - 744..757 '[box Astruct]': [Box<dyn B, Global>; 1] - 745..756 'box Astruct': Box<Astruct, Global> - 749..756 'Astruct': Astruct + 604..608 'self': Box<[T], A> + 637..669 '{ ... }': Vec<T, A> + 683..796 '{ ...t]); }': () + 693..696 'vec': Vec<i32, Global> + 699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global> + 699..726 '<[_]>:...1i32])': Vec<i32, Global> + 715..725 'box [1i32]': Box<[i32; 1], Global> + 719..725 '[1i32]': [i32; 1] + 720..724 '1i32': i32 + 736..737 'v': Vec<Box<dyn B, Global>, Global> + 757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global> + 757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global> + 775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global> + 779..792 '[box Astruct]': [Box<dyn B, Global>; 1] + 780..791 'box Astruct': Box<Astruct, Global> + 784..791 'Astruct': Astruct "#]], ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 015085bde45..da76d7fd83f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -83,6 +83,46 @@ async fn test() { } #[test] +fn infer_async_closure() { + check_types( + r#" +//- minicore: future, option +async fn test() { + let f = async move |x: i32| x + 42; + f; +// ^ |i32| -> impl Future<Output = i32> + let a = f(4); + a; +// ^ impl Future<Output = i32> + let x = a.await; + x; +// ^ i32 + let f = async move || 42; + f; +// ^ || -> impl Future<Output = i32> + let a = f(); + a; +// ^ impl Future<Output = i32> + let x = a.await; + x; +// ^ i32 + let b = ((async move || {})()).await; + b; +// ^ () + let c = async move || { + let y = None; + y + // ^ Option<u64> + }; + let _: Option<u64> = c().await; + c; +// ^ || -> impl Future<Output = Option<u64>> +} +"#, + ); +} + +#[test] fn auto_sized_async_block() { check_no_mismatches( r#" @@ -493,29 +533,30 @@ fn tuple_struct_with_fn() { r#" struct S(fn(u32) -> u64); fn test() -> u64 { - let a = S(|i| 2*i); + let a = S(|i| 2*i as u64); let b = a.0(4); a.0(2) }"#, expect![[r#" - 43..101 '{ ...0(2) }': u64 + 43..108 '{ ...0(2) }': u64 53..54 'a': S 57..58 'S': S(fn(u32) -> u64) -> S - 57..67 'S(|i| 2*i)': S - 59..66 '|i| 2*i': |u32| -> u64 + 57..74 'S(|i| ...s u64)': S + 59..73 '|i| 2*i as u64': |u32| -> u64 60..61 'i': u32 - 63..64 '2': u32 - 63..66 '2*i': u32 + 63..64 '2': u64 + 63..73 '2*i as u64': u64 65..66 'i': u32 - 77..78 'b': u64 - 81..82 'a': S - 81..84 'a.0': fn(u32) -> u64 - 81..87 'a.0(4)': u64 - 85..86 '4': u32 - 93..94 'a': S - 93..96 'a.0': fn(u32) -> u64 - 93..99 'a.0(2)': u64 - 97..98 '2': u32 + 65..73 'i as u64': u64 + 84..85 'b': u64 + 88..89 'a': S + 88..91 'a.0': fn(u32) -> u64 + 88..94 'a.0(4)': u64 + 92..93 '4': u32 + 100..101 'a': S + 100..103 'a.0': fn(u32) -> u64 + 100..106 'a.0(2)': u64 + 104..105 '2': u32 "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs index cd465739139..0935b5ea519 100644 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir/src/db.rs @@ -5,7 +5,7 @@ //! But we need this for at least LRU caching at the query level. pub use hir_def::db::*; pub use hir_expand::db::{ - AstDatabase, AstDatabaseStorage, AstIdMapQuery, ExpandProcMacroQuery, HygieneFrameQuery, + AstIdMapQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, HygieneFrameQuery, InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandErrorQuery, MacroExpandQuery, ParseMacroExpansionQuery, }; diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 8f019a81b2d..253d62dafc6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -3,6 +3,8 @@ //! //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. +pub use hir_ty::diagnostics::{IncoherentImpl, IncorrectCase}; + use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use either::Either; @@ -35,6 +37,7 @@ diagnostics![ InactiveCode, IncorrectCase, InvalidDeriveTarget, + IncoherentImpl, MacroError, MalformedDerive, MismatchedArgCount, @@ -220,5 +223,3 @@ pub struct NeedMut { pub struct UnusedMut { pub local: Local, } - -pub use hir_ty::diagnostics::IncorrectCase; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 25c07a2fbd3..35424feec8b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -85,10 +85,10 @@ use crate::db::{DefDatabase, HirDatabase}; pub use crate::{ attrs::{HasAttrs, Namespace}, diagnostics::{ - AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncorrectCase, - InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields, - MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, PrivateField, - ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro, + AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl, + IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, + MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, + PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut, }, @@ -604,11 +604,23 @@ impl Module { } } + let inherent_impls = db.inherent_impls_in_crate(self.id.krate()); + for impl_def in self.impl_defs(db) { for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { emit_def_diagnostic(db, acc, diag); } + if inherent_impls.invalid_impls().contains(&impl_def.id) { + let loc = impl_def.id.lookup(db.upcast()); + let tree = loc.id.item_tree(db.upcast()); + let node = &tree[loc.id.value]; + let file_id = loc.id.file_id(); + let ast_id_map = db.ast_id_map(file_id); + + acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + } + for item in impl_def.items(db) { let def: DefWithBody = match item { AssocItem::Function(it) => it.into(), @@ -3210,6 +3222,14 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize))) } + pub fn is_float(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Float(_))) + } + + pub fn is_char(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Char)) + } + pub fn is_int_or_uint(&self) -> bool { match self.ty.kind(Interner) { TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) => true, @@ -3224,6 +3244,13 @@ impl Type { } } + pub fn as_slice(&self) -> Option<Type> { + match &self.ty.kind(Interner) { + TyKind::Slice(ty) => Some(self.derived(ty.clone())), + _ => None, + } + } + pub fn strip_references(&self) -> Type { self.derived(self.ty.strip_references().clone()) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 8bd905d0113..407ba6f6584 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -15,7 +15,7 @@ use hir_def::{ AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId, }; use hir_expand::{ - db::AstDatabase, + db::ExpandDatabase, name::{known, AsName}, ExpansionInfo, MacroCallId, }; @@ -411,7 +411,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_record_field(field) } - pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> { + pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> { self.imp.resolve_record_pat_field(field) } @@ -1201,7 +1201,7 @@ impl<'db> SemanticsImpl<'db> { self.analyze(field.syntax())?.resolve_record_field(self.db, field) } - fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> { + fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> { self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field) } @@ -1536,7 +1536,7 @@ impl<'db> SemanticsImpl<'db> { fn macro_call_to_macro_id( ctx: &mut SourceToDefCtx<'_, '_>, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, macro_call_id: MacroCallId, ) -> Option<MacroId> { let loc = db.lookup_intern_macro_call(macro_call_id); diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 133fa810d66..c24d196e1b6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -441,14 +441,17 @@ impl SourceAnalyzer { &self, db: &dyn HirDatabase, field: &ast::RecordPatField, - ) -> Option<Field> { + ) -> Option<(Field, Type)> { let field_name = field.field_name()?.as_name(); let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let pat_id = self.pat_id(&record_pat.into())?; let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?; let variant_data = variant.variant_data(db.upcast()); let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; - Some(field.into()) + let (_, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id)?.as_adt()?; + let field_ty = + db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst); + Some((field.into(), Type::new_with_resolver(db, &self.resolver, field_ty))) } pub(crate) fn resolve_macro_call( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index eef037f9875..0768389281c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -1027,7 +1027,7 @@ fn next_space_for_fn_after_call_site(expr: ast::CallableExpr) -> Option<Generate } fn next_space_for_fn_in_module( - db: &dyn hir::db::AstDatabase, + db: &dyn hir::db::ExpandDatabase, module_source: &hir::InFile<hir::ModuleSource>, ) -> Option<(FileId, GeneratedFunctionTarget)> { let file = module_source.file_id.original_file(db); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 5ac18727c19..28d815e81b4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -363,10 +363,10 @@ fn inline( .collect(); if function.self_param(sema.db).is_some() { - let this = || make::name_ref("this").syntax().clone_for_update(); + let this = || make::name_ref("this").syntax().clone_for_update().first_token().unwrap(); if let Some(self_local) = params[0].2.as_local(sema.db) { usages_for_locals(self_local) - .flat_map(|FileReference { name, range, .. }| match name { + .filter_map(|FileReference { name, range, .. }| match name { ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)), _ => None, }) @@ -691,6 +691,42 @@ fn main() { } #[test] + fn generic_method_by_ref() { + check_assist( + inline_call, + r#" +struct Foo(u32); + +impl Foo { + fn add<T>(&self, a: u32) -> Self { + Foo(self.0 + a) + } +} + +fn main() { + let x = Foo(3).add$0::<usize>(2); +} +"#, + r#" +struct Foo(u32); + +impl Foo { + fn add<T>(&self, a: u32) -> Self { + Foo(self.0 + a) + } +} + +fn main() { + let x = { + let ref this = Foo(3); + Foo(this.0 + 2) + }; +} +"#, + ); + } + + #[test] fn method_by_ref_mut() { check_assist( inline_call, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs index 1361cdf00cc..a403d5bc672 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs @@ -46,7 +46,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( acc.add( AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", - ctx.selection_trimmed(), + replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range)).unwrap(), |builder| { for (range, expr) in replacements { if let Some(expr) = expr { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 4d489b62b5c..8b07e29a587 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -265,7 +265,6 @@ mod handlers { inline_local_variable::inline_local_variable, inline_type_alias::inline_type_alias, inline_type_alias::inline_type_alias_uses, - inline_macro::inline_macro, introduce_named_generic::introduce_named_generic, introduce_named_lifetime::introduce_named_lifetime, invert_if::invert_if, @@ -286,7 +285,6 @@ mod handlers { raw_string::add_hash, raw_string::make_usual_string, raw_string::remove_hash, - remove_dbg::remove_dbg, remove_mut::remove_mut, remove_unused_param::remove_unused_param, remove_parentheses::remove_parentheses, @@ -335,6 +333,9 @@ mod handlers { generate_setter::generate_setter, generate_delegate_methods::generate_delegate_methods, generate_deref::generate_deref, + // + remove_dbg::remove_dbg, + inline_macro::inline_macro, // Are you sure you want to add new assist here, and not to the // sorted list above? ] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index eb87d6c5826..c3136f6df4b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -23,7 +23,7 @@ pub(crate) mod env_vars; use std::iter; -use hir::{known, ScopeDef}; +use hir::{known, ScopeDef, Variant}; use ide_db::{imports::import_assets::LocatedImport, SymbolKind}; use syntax::ast; @@ -537,17 +537,20 @@ fn enum_variants_with_paths( impl_: &Option<ast::Impl>, cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath), ) { + let mut process_variant = |variant: Variant| { + let self_path = hir::ModPath::from_segments( + hir::PathKind::Plain, + iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))), + ); + + cb(acc, ctx, variant, self_path); + }; + let variants = enum_.variants(ctx.db); if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { - for &variant in &variants { - let self_path = hir::ModPath::from_segments( - hir::PathKind::Plain, - iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))), - ); - cb(acc, ctx, variant, self_path); - } + variants.iter().for_each(|variant| process_variant(*variant)); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index 09ac57153ae..77246379e7b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -415,7 +415,6 @@ fn foo(a: lib::A) { a.$0 } fn test_local_impls() { check( r#" -//- /lib.rs crate:lib pub struct A {} mod m { impl super::A { @@ -427,9 +426,8 @@ mod m { } } } -//- /main.rs crate:main deps:lib -fn foo(a: lib::A) { - impl lib::A { +fn foo(a: A) { + impl A { fn local_method(&self) {} } a.$0 diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 7dc29c3d5ac..8cbf89e9c30 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -220,6 +220,8 @@ pub(super) struct PatternContext { /// The record pattern this name or ref is a field of pub(super) record_pat: Option<ast::RecordPat>, pub(super) impl_: Option<ast::Impl>, + /// List of missing variants in a match expr + pub(super) missing_variants: Vec<hir::Variant>, } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index db0045aef6e..a94c404586b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1,7 +1,7 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; -use hir::{Semantics, Type, TypeInfo}; +use hir::{Semantics, Type, TypeInfo, Variant}; use ide_db::{active_parameter::ActiveParameter, RootDatabase}; use syntax::{ algo::{find_node_at_offset, non_trivia_sibling}, @@ -353,7 +353,7 @@ fn expected_type_and_name( _ => ty, }; - loop { + let (ty, name) = loop { break match_ast! { match node { ast::LetStmt(it) => { @@ -385,9 +385,7 @@ fn expected_type_and_name( token.clone(), ).map(|ap| { let name = ap.ident().map(NameOrNameRef::Name); - - let ty = strip_refs(ap.ty); - (Some(ty), name) + (Some(ap.ty), name) }) .unwrap_or((None, None)) }, @@ -489,7 +487,8 @@ fn expected_type_and_name( }, } }; - } + }; + (ty.map(strip_refs), name) } fn classify_lifetime( @@ -1133,6 +1132,9 @@ fn pattern_context_for( pat: ast::Pat, ) -> PatternContext { let mut param_ctx = None; + + let mut missing_variants = vec![]; + let (refutability, has_type_ascription) = pat .syntax() @@ -1162,7 +1164,52 @@ fn pattern_context_for( })(); return (PatternRefutability::Irrefutable, has_type_ascription) }, - ast::MatchArm(_) => PatternRefutability::Refutable, + ast::MatchArm(match_arm) => { + let missing_variants_opt = match_arm + .syntax() + .parent() + .and_then(ast::MatchArmList::cast) + .and_then(|match_arm_list| { + match_arm_list + .syntax() + .parent() + .and_then(ast::MatchExpr::cast) + .and_then(|match_expr| { + let expr_opt = find_opt_node_in_file(&original_file, match_expr.expr()); + + expr_opt.and_then(|expr| { + sema.type_of_expr(&expr)? + .adjusted() + .autoderef(sema.db) + .find_map(|ty| match ty.as_adt() { + Some(hir::Adt::Enum(e)) => Some(e), + _ => None, + }).and_then(|enum_| { + Some(enum_.variants(sema.db)) + }) + }) + }).and_then(|variants| { + Some(variants.iter().filter_map(|variant| { + let variant_name = variant.name(sema.db).to_string(); + + let variant_already_present = match_arm_list.arms().any(|arm| { + arm.pat().and_then(|pat| { + let pat_already_present = pat.syntax().to_string().contains(&variant_name); + pat_already_present.then(|| pat_already_present) + }).is_some() + }); + + (!variant_already_present).then_some(variant.clone()) + }).collect::<Vec<Variant>>()) + }) + }); + + if let Some(missing_variants_) = missing_variants_opt { + missing_variants = missing_variants_; + }; + + PatternRefutability::Refutable + }, ast::LetExpr(_) => PatternRefutability::Refutable, ast::ForExpr(_) => PatternRefutability::Irrefutable, _ => PatternRefutability::Irrefutable, @@ -1184,6 +1231,7 @@ fn pattern_context_for( ref_token, record_pat: None, impl_: fetch_immediate_impl(sema, original_file, pat.syntax()), + missing_variants, } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index a654a5db574..82a1c10c531 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -411,3 +411,15 @@ fn main() { expect!["ty: i32, name: ?"], ); } + +#[test] +fn expected_type_ref_return_pos() { + check_expected_type_and_name( + r#" +fn f(thing: u32) -> &u32 { + &thin$0 +} +"#, + expect!["ty: u32, name: ?"], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs index 21b4bc2174b..9225c91bebf 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs @@ -37,7 +37,9 @@ pub(crate) fn render_struct_pat( let lookup = format_literal_lookup(name.as_str(), kind); let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; - Some(build_completion(ctx, label, lookup, pat, strukt)) + let db = ctx.db(); + + Some(build_completion(ctx, label, lookup, pat, strukt, strukt.ty(db), false)) } pub(crate) fn render_variant_pat( @@ -52,6 +54,7 @@ pub(crate) fn render_variant_pat( let fields = variant.fields(ctx.db()); let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?; + let enum_ty = variant.parent_enum(ctx.db()).ty(ctx.db()); let (name, escaped_name) = match path { Some(path) => (path.unescaped().to_string().into(), path.to_string().into()), @@ -81,7 +84,15 @@ pub(crate) fn render_variant_pat( } }; - Some(build_completion(ctx, label, lookup, pat, variant)) + Some(build_completion( + ctx, + label, + lookup, + pat, + variant, + enum_ty, + pattern_ctx.missing_variants.contains(&variant), + )) } fn build_completion( @@ -90,13 +101,22 @@ fn build_completion( lookup: SmolStr, pat: String, def: impl HasAttrs + Copy, + adt_ty: hir::Type, + // Missing in context of match statement completions + is_variant_missing: bool, ) -> CompletionItem { + let mut relevance = ctx.completion_relevance(); + + if is_variant_missing { + relevance.type_match = super::compute_type_match(ctx.completion, &adt_ty); + } + let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label); item.set_documentation(ctx.docs(def)) .set_deprecated(ctx.is_deprecated(def)) .detail(&pat) .lookup_by(lookup) - .set_relevance(ctx.completion_relevance()); + .set_relevance(relevance); match ctx.snippet_cap() { Some(snippet_cap) => item.insert_snippet(snippet_cap, pat), None => item.insert_text(pat), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs index ad9254e7f2e..c0e485c36fd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs @@ -614,6 +614,7 @@ fn f(u: U) { check_empty( r#" +#![rustc_coherence_is_core] #[lang = "u32"] impl u32 { pub const MIN: Self = 0; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs index 328faaa060f..65cefdb0856 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs @@ -47,6 +47,66 @@ fn foo(s: Struct) { } #[test] +fn record_pattern_field_enum() { + check( + r#" +//- minicore:result +enum Baz { Foo, Bar } + +fn foo(baz: Baz) { + match baz { + Baz::Foo => (), + $0 + } +} +"#, + expect![[r#" + en Baz + en Result + md core + ev Err + ev Ok + bn Baz::Bar Baz::Bar$0 + bn Baz::Foo Baz::Foo$0 + bn Err(…) Err($1)$0 + bn Ok(…) Ok($1)$0 + kw mut + kw ref + "#]], + ); + + check( + r#" +//- minicore:result +enum Baz { Foo, Bar } + +fn foo(baz: Baz) { + use Baz::*; + match baz { + Foo => (), + $0 + } +} + "#, + expect![[r#" + en Baz + en Result + md core + ev Bar + ev Err + ev Foo + ev Ok + bn Bar Bar$0 + bn Err(…) Err($1)$0 + bn Foo Foo$0 + bn Ok(…) Ok($1)$0 + kw mut + kw ref + "#]], + ); +} + +#[test] fn pattern_enum_variant() { check( r#" diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index cb71c7b2bde..f8a6f6cd3ed 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -608,6 +608,7 @@ fn f() { } //- /core.rs crate:core +#![rustc_coherence_is_core] #[lang = "u8"] impl u8 { pub const MAX: Self = 255; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index 244e99fe2e2..ea1d9cc4919 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -71,7 +71,7 @@ impl RootDatabase { base_db::SourceRootQuery base_db::SourceRootCratesQuery - // AstDatabase + // ExpandDatabase hir::db::AstIdMapQuery hir::db::ParseMacroExpansionQuery hir::db::InternMacroCallQuery diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 1322f5228e8..4071c490b7f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -327,7 +327,7 @@ impl NameClass { let pat_parent = ident_pat.syntax().parent(); if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) { if record_pat_field.name_ref().is_none() { - if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) { + if let Some((field, _)) = sema.resolve_record_pat_field(&record_pat_field) { return Some(NameClass::PatFieldShorthand { local_def: local, field_ref: field, @@ -483,6 +483,13 @@ impl NameRefClass { }, ast::RecordPatField(record_pat_field) => { sema.resolve_record_pat_field(&record_pat_field) + .map(|(field, ..)|field) + .map(Definition::Field) + .map(NameRefClass::Definition) + }, + ast::RecordExprField(record_expr_field) => { + sema.resolve_record_field(&record_expr_field) + .map(|(field, ..)|field) .map(Definition::Field) .map(NameRefClass::Definition) }, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index ae120470047..b1df11bf911 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -50,7 +50,7 @@ use base_db::{ AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast, }; use hir::{ - db::{AstDatabase, DefDatabase, HirDatabase}, + db::{DefDatabase, ExpandDatabase, HirDatabase}, symbols::FileSymbolKind, }; use stdx::hash::NoHashHashSet; @@ -68,7 +68,7 @@ pub type FxIndexMap<K, V> = #[salsa::database( base_db::SourceDatabaseExtStorage, base_db::SourceDatabaseStorage, - hir::db::AstDatabaseStorage, + hir::db::ExpandDatabaseStorage, hir::db::DefDatabaseStorage, hir::db::HirDatabaseStorage, hir::db::InternDatabaseStorage, @@ -95,8 +95,8 @@ impl fmt::Debug for RootDatabase { } } -impl Upcast<dyn AstDatabase> for RootDatabase { - fn upcast(&self) -> &(dyn AstDatabase + 'static) { +impl Upcast<dyn ExpandDatabase> for RootDatabase { + fn upcast(&self) -> &(dyn ExpandDatabase + 'static) { &*self } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs new file mode 100644 index 00000000000..72af9ebfcbb --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs @@ -0,0 +1,77 @@ +use hir::InFile; + +use crate::{Diagnostic, DiagnosticsContext, Severity}; + +// Diagnostic: incoherent-impl +// +// This diagnostic is triggered if the targe type of an impl is from a foreign crate. +pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentImpl) -> Diagnostic { + Diagnostic::new( + "incoherent-impl", + format!("cannot define inherent `impl` for foreign type"), + ctx.sema.diagnostics_display_range(InFile::new(d.file_id, d.impl_.clone().into())).range, + ) + .severity(Severity::Error) +} + +#[cfg(test)] +mod change_case { + use crate::tests::check_diagnostics; + + #[test] + fn primitive() { + check_diagnostics( + r#" + impl bool {} +//^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type +"#, + ); + } + + #[test] + fn primitive_rustc_allow_incoherent_impl() { + check_diagnostics( + r#" +impl bool { + #[rustc_allow_incoherent_impl] + fn falsch(self) -> Self { false } +} +"#, + ); + } + + #[test] + fn rustc_allow_incoherent_impl() { + check_diagnostics( + r#" +//- /lib.rs crate:foo +#[rustc_has_incoherent_inherent_impls] +pub struct S; +//- /main.rs crate:main deps:foo +impl foo::S { + #[rustc_allow_incoherent_impl] + fn func(self) {} +} +"#, + ); + check_diagnostics( + r#" +//- /lib.rs crate:foo +pub struct S; +//- /main.rs crate:main deps:foo + impl foo::S { #[rustc_allow_incoherent_impl] fn func(self) {} } +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type +"#, + ); + check_diagnostics( + r#" +//- /lib.rs crate:foo +#[rustc_has_incoherent_inherent_impls] +pub struct S; +//- /main.rs crate:main deps:foo + impl foo::S { fn func(self) {} } +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 6a78c08d44c..db88bf7b931 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -1,4 +1,4 @@ -use hir::{db::AstDatabase, InFile}; +use hir::{db::ExpandDatabase, InFile}; use ide_db::{assists::Assist, defs::NameClass}; use syntax::AstNode; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 14039087b3f..5c4327ff934 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -1,6 +1,6 @@ use either::Either; use hir::{ - db::{AstDatabase, HirDatabase}, + db::{ExpandDatabase, HirDatabase}, known, AssocItem, HirDisplay, InFile, Type, }; use ide_db::{ diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index ea1ea5a216d..eb32db25065 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -1,4 +1,10 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use hir::db::ExpandDatabase; +use ide_db::{assists::Assist, source_change::SourceChange}; +use syntax::{ast, SyntaxNode}; +use syntax::{match_ast, AstNode}; +use text_edit::TextEdit; + +use crate::{fix, Diagnostic, DiagnosticsContext}; // Diagnostic: missing-unsafe // @@ -9,11 +15,83 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf "this operation is unsafe and requires an unsafe function or block", ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, ) + .with_fixes(fixes(ctx, d)) +} + +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Assist>> { + // The fixit will not work correctly for macro expansions, so we don't offer it in that case. + if d.expr.file_id.is_macro() { + return None; + } + + let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?; + let expr = d.expr.value.to_node(&root); + + let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?; + + let replacement = format!("unsafe {{ {} }}", node_to_add_unsafe_block.text()); + let edit = TextEdit::replace(node_to_add_unsafe_block.text_range(), replacement); + let source_change = + SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit); + Some(vec![fix("add_unsafe", "Add unsafe block", source_change, expr.syntax().text_range())]) +} + +// Pick the first ancestor expression of the unsafe `expr` that is not a +// receiver of a method call, a field access, the left-hand side of an +// assignment, or a reference. As all of those cases would incur a forced move +// if wrapped which might not be wanted. That is: +// - `unsafe_expr.foo` -> `unsafe { unsafe_expr.foo }` +// - `unsafe_expr.foo.bar` -> `unsafe { unsafe_expr.foo.bar }` +// - `unsafe_expr.foo()` -> `unsafe { unsafe_expr.foo() }` +// - `unsafe_expr.foo.bar()` -> `unsafe { unsafe_expr.foo.bar() }` +// - `unsafe_expr += 1` -> `unsafe { unsafe_expr += 1 }` +// - `&unsafe_expr` -> `unsafe { &unsafe_expr }` +// - `&&unsafe_expr` -> `unsafe { &&unsafe_expr }` +fn pick_best_node_to_add_unsafe_block(unsafe_expr: &ast::Expr) -> Option<SyntaxNode> { + // The `unsafe_expr` might be: + // - `ast::CallExpr`: call an unsafe function + // - `ast::MethodCallExpr`: call an unsafe method + // - `ast::PrefixExpr`: dereference a raw pointer + // - `ast::PathExpr`: access a static mut variable + for (node, parent) in + unsafe_expr.syntax().ancestors().zip(unsafe_expr.syntax().ancestors().skip(1)) + { + match_ast! { + match parent { + // If the `parent` is a `MethodCallExpr`, that means the `node` + // is the receiver of the method call, because only the receiver + // can be a direct child of a method call. The method name + // itself is not an expression but a `NameRef`, and an argument + // is a direct child of an `ArgList`. + ast::MethodCallExpr(_) => continue, + ast::FieldExpr(_) => continue, + ast::RefExpr(_) => continue, + ast::BinExpr(it) => { + // Check if the `node` is the left-hand side of an + // assignment, if so, we don't want to wrap it in an unsafe + // block, e.g. `unsafe_expr += 1` + let is_left_hand_side_of_assignment = { + if let Some(ast::BinaryOp::Assignment { .. }) = it.op_kind() { + it.lhs().map(|lhs| lhs.syntax().text_range().contains_range(node.text_range())).unwrap_or(false) + } else { + false + } + }; + if !is_left_hand_side_of_assignment { + return Some(node); + } + }, + _ => { return Some(node); } + + } + } + } + None } #[cfg(test)] mod tests { - use crate::tests::check_diagnostics; + use crate::tests::{check_diagnostics, check_fix, check_no_fix}; #[test] fn missing_unsafe_diagnostic_with_raw_ptr() { @@ -23,7 +101,7 @@ fn main() { let x = &5 as *const usize; unsafe { let y = *x; } let z = *x; -} //^^ error: this operation is unsafe and requires an unsafe function or block +} //^^💡 error: this operation is unsafe and requires an unsafe function or block "#, ) } @@ -48,9 +126,9 @@ unsafe fn unsafe_fn() { fn main() { unsafe_fn(); - //^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block HasUnsafe.unsafe_fn(); - //^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block unsafe { unsafe_fn(); HasUnsafe.unsafe_fn(); @@ -72,7 +150,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 }; fn main() { let x = STATIC_MUT.a; - //^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block unsafe { let x = STATIC_MUT.a; } @@ -94,9 +172,298 @@ extern "rust-intrinsic" { fn main() { let _ = bitreverse(12); let _ = floorf32(12.0); - //^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block } "#, ); } + + #[test] + fn add_unsafe_block_when_dereferencing_a_raw_pointer() { + check_fix( + r#" +fn main() { + let x = &5 as *const usize; + let z = *x$0; +} +"#, + r#" +fn main() { + let x = &5 as *const usize; + let z = unsafe { *x }; +} +"#, + ); + } + + #[test] + fn add_unsafe_block_when_calling_unsafe_function() { + check_fix( + r#" +unsafe fn func() { + let x = &5 as *const usize; + let z = *x; +} +fn main() { + func$0(); +} +"#, + r#" +unsafe fn func() { + let x = &5 as *const usize; + let z = *x; +} +fn main() { + unsafe { func() }; +} +"#, + ) + } + + #[test] + fn add_unsafe_block_when_calling_unsafe_method() { + check_fix( + r#" +struct S(usize); +impl S { + unsafe fn func(&self) { + let x = &self.0 as *const usize; + let z = *x; + } +} +fn main() { + let s = S(5); + s.func$0(); +} +"#, + r#" +struct S(usize); +impl S { + unsafe fn func(&self) { + let x = &self.0 as *const usize; + let z = *x; + } +} +fn main() { + let s = S(5); + unsafe { s.func() }; +} +"#, + ) + } + + #[test] + fn add_unsafe_block_when_accessing_mutable_static() { + check_fix( + r#" +struct Ty { + a: u8, +} + +static mut STATIC_MUT: Ty = Ty { a: 0 }; + +fn main() { + let x = STATIC_MUT$0.a; +} +"#, + r#" +struct Ty { + a: u8, +} + +static mut STATIC_MUT: Ty = Ty { a: 0 }; + +fn main() { + let x = unsafe { STATIC_MUT.a }; +} +"#, + ) + } + + #[test] + fn add_unsafe_block_when_calling_unsafe_intrinsic() { + check_fix( + r#" +extern "rust-intrinsic" { + pub fn floorf32(x: f32) -> f32; +} + +fn main() { + let _ = floorf32$0(12.0); +} +"#, + r#" +extern "rust-intrinsic" { + pub fn floorf32(x: f32) -> f32; +} + +fn main() { + let _ = unsafe { floorf32(12.0) }; +} +"#, + ) + } + + #[test] + fn unsafe_expr_as_a_receiver_of_a_method_call() { + check_fix( + r#" +unsafe fn foo() -> String { + "string".to_string() +} + +fn main() { + foo$0().len(); +} +"#, + r#" +unsafe fn foo() -> String { + "string".to_string() +} + +fn main() { + unsafe { foo().len() }; +} +"#, + ) + } + + #[test] + fn unsafe_expr_as_an_argument_of_a_method_call() { + check_fix( + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let mut v = vec![]; + v.push(STATIC_MUT$0); +} +"#, + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let mut v = vec![]; + v.push(unsafe { STATIC_MUT }); +} +"#, + ) + } + + #[test] + fn unsafe_expr_as_left_hand_side_of_assignment() { + check_fix( + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + STATIC_MUT$0 = 1; +} +"#, + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + unsafe { STATIC_MUT = 1 }; +} +"#, + ) + } + + #[test] + fn unsafe_expr_as_right_hand_side_of_assignment() { + check_fix( + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let x; + x = STATIC_MUT$0; +} +"#, + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let x; + x = unsafe { STATIC_MUT }; +} +"#, + ) + } + + #[test] + fn unsafe_expr_in_binary_plus() { + check_fix( + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let x = STATIC_MUT$0 + 1; +} +"#, + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let x = unsafe { STATIC_MUT } + 1; +} +"#, + ) + } + + #[test] + fn ref_to_unsafe_expr() { + check_fix( + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let x = &STATIC_MUT$0; +} +"#, + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let x = unsafe { &STATIC_MUT }; +} +"#, + ) + } + + #[test] + fn ref_ref_to_unsafe_expr() { + check_fix( + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let x = &&STATIC_MUT$0; +} +"#, + r#" +static mut STATIC_MUT: u8 = 0; + +fn main() { + let x = unsafe { &&STATIC_MUT }; +} +"#, + ) + } + + #[test] + fn unsafe_expr_in_macro_call() { + check_no_fix( + r#" +unsafe fn foo() -> u8 { + 0 +} + +fn main() { + let x = format!("foo: {}", foo$0()); +} + "#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 84189a5d560..96470265d11 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -506,6 +506,30 @@ fn main() { } #[test] + fn initialization_is_not_mutation_in_loop() { + check_diagnostics( + r#" +fn main() { + let a; + loop { + let c @ ( + mut b, + //^^^^^ 💡 weak: variable does not need to be mutable + mut d + //^^^^^ 💡 weak: variable does not need to be mutable + ); + a = 1; + //^^^^^ 💡 error: cannot mutate immutable variable `a` + b = 1; + c = (2, 3); + d = 3; + } +} +"#, + ); + } + + #[test] fn function_arguments_are_initialized() { check_diagnostics( r#" diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index 8da04e628d6..24c521ed1a8 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,4 +1,4 @@ -use hir::{db::AstDatabase, HasSource, HirDisplay, Semantics}; +use hir::{db::ExpandDatabase, HasSource, HirDisplay, Semantics}; use ide_db::{base_db::FileId, source_change::SourceChange, RootDatabase}; use syntax::{ ast::{self, edit::IndentLevel, make}, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs index e630ae36866..be83ad6aaad 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs @@ -65,4 +65,24 @@ fn main(s: module::Struct) { "#, ); } + + #[test] + fn block_module_madness() { + check_diagnostics( + r#" +fn main() { + let strukt = { + use crate as ForceParentBlockDefMap; + { + pub struct Struct { + field: (), + } + Struct { field: () } + } + }; + strukt.field; +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index a0c276cc332..9b1c65983e6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -1,4 +1,4 @@ -use hir::{db::AstDatabase, InFile}; +use hir::{db::ExpandDatabase, InFile}; use ide_db::source_change::SourceChange; use syntax::{ ast::{self, HasArgList}, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index b57a13e53e6..4abc25a28fb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{db::AstDatabase, HirDisplay, InFile, Type}; +use hir::{db::ExpandDatabase, HirDisplay, InFile, Type}; use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; use syntax::{ ast::{self, BlockExpr, ExprStmt}, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 7de03416e56..cefa74e523e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -1,4 +1,4 @@ -use hir::{db::AstDatabase, HirDisplay, InFile}; +use hir::{db::ExpandDatabase, HirDisplay, InFile}; use ide_db::{ assists::{Assist, AssistId, AssistKind}, base_db::FileRange, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 4b0e64cb896..f3ec6efa752 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -1,4 +1,4 @@ -use hir::{db::AstDatabase, HirDisplay}; +use hir::{db::ExpandDatabase, HirDisplay}; use ide_db::{ assists::{Assist, AssistId, AssistKind}, base_db::FileRange, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs index 91395f1d841..94614f11c33 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs @@ -1,4 +1,4 @@ -use hir::db::AstDatabase; +use hir::db::ExpandDatabase; use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit}; use itertools::Itertools; use syntax::AstNode; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index f6c9b79c30c..71f136b8c90 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -29,6 +29,7 @@ mod handlers { pub(crate) mod break_outside_of_loop; pub(crate) mod expected_function; pub(crate) mod inactive_code; + pub(crate) mod incoherent_impl; pub(crate) mod incorrect_case; pub(crate) mod invalid_derive_target; pub(crate) mod macro_error; @@ -254,6 +255,7 @@ pub fn diagnostics( AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d), AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d), AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d), + AnyDiagnostic::IncoherentImpl(d) => handlers::incoherent_impl::incoherent_impl(&ctx, &d), AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d), AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d), diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs index 190ab80ba0f..a1a119629a9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs @@ -297,6 +297,7 @@ impl Foo<str> {} //- /lib.rs crate:main deps:core fn foo(_: bool$0) {{}} //- /libcore.rs crate:core +#![rustc_coherence_is_core] #[lang = "bool"] impl bool {} //^^^^ diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index 55cdb3200ea..6d2d0bd6351 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -55,7 +55,7 @@ pub(crate) fn goto_type_definition( ty } else { let record_field = ast::RecordPatField::for_field_name_ref(&it)?; - sema.resolve_record_pat_field(&record_field)?.ty(db) + sema.resolve_record_pat_field(&record_field)?.1 } }, _ => return None, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 729780fa0c9..46505b30441 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -31,19 +31,31 @@ pub(super) fn hints( return None; } - // These inherit from the inner expression which would result in duplicate hints - if let ast::Expr::ParenExpr(_) - | ast::Expr::IfExpr(_) - | ast::Expr::BlockExpr(_) - | ast::Expr::MatchExpr(_) = expr - { + // ParenExpr resolve to their contained expressions HIR so they will dupe these hints + if let ast::Expr::ParenExpr(_) = expr { return None; } + if let ast::Expr::BlockExpr(b) = expr { + if !b.is_standalone() { + return None; + } + } let descended = sema.descend_node_into_attributes(expr.clone()).pop(); let desc_expr = descended.as_ref().unwrap_or(expr); let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; + if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr { + if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] = + &*adjustments + { + // Don't show unnecessary reborrows for these, they will just repeat the inner ones again + if source == target { + return None; + } + } + } + let (postfix, needs_outer_parens, needs_inner_parens) = mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode); @@ -67,6 +79,7 @@ pub(super) fn hints( for Adjustment { source, target, kind } in iter { if source == target { + cov_mark::hit!(same_type_adjustment); continue; } @@ -251,7 +264,7 @@ mod tests { check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized, fn +//- minicore: coerce_unsized, fn, eq fn main() { let _: u32 = loop {}; //^^^^^^^<never-to-any> @@ -332,7 +345,7 @@ fn main() { loop {} //^^^^^^^<never-to-any> }; - let _: &mut [u32] = match () { () => &mut [] } + let _: &mut [u32] = match () { () => &mut [] }; //^^^^^^^<unsize> //^^^^^^^&mut $ //^^^^^^^* @@ -341,6 +354,12 @@ fn main() { //^^^^^^^^^^<unsize> //^^^^^^^^^^&mut $ //^^^^^^^^^^* + () == (); + // ^^& + // ^^& + (()) == {()}; + // ^^& + // ^^^^& } #[derive(Copy, Clone)] @@ -363,7 +382,7 @@ impl Struct { ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized, fn +//- minicore: coerce_unsized, fn, eq fn main() { Struct.consume(); @@ -419,7 +438,7 @@ fn main() { loop {} //^^^^^^^.<never-to-any> }; - let _: &mut [u32] = match () { () => &mut [] } + let _: &mut [u32] = match () { () => &mut [] }; //^^^^^^^( //^^^^^^^) //^^^^^^^.* @@ -432,6 +451,12 @@ fn main() { //^^^^^^^^^^.* //^^^^^^^^^^.&mut //^^^^^^^^^^.<unsize> + () == (); + // ^^.& + // ^^.& + (()) == {()}; + // ^^.& + // ^^^^.& } #[derive(Copy, Clone)] @@ -499,6 +524,7 @@ fn main() { #[test] fn never_to_never_is_never_shown() { + cov_mark::check!(same_type_adjustment); check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, r#" diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index 0a7513e465a..1e1771259b1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -435,7 +435,7 @@ fn main() { file_id: FileId( 1, ), - range: 3386..3394, + range: 3415..3423, }, ), tooltip: "", @@ -448,7 +448,7 @@ fn main() { file_id: FileId( 1, ), - range: 3418..3422, + range: 3447..3451, }, ), tooltip: "", @@ -468,7 +468,7 @@ fn main() { file_id: FileId( 1, ), - range: 3386..3394, + range: 3415..3423, }, ), tooltip: "", @@ -481,7 +481,7 @@ fn main() { file_id: FileId( 1, ), - range: 3418..3422, + range: 3447..3451, }, ), tooltip: "", @@ -501,7 +501,7 @@ fn main() { file_id: FileId( 1, ), - range: 3386..3394, + range: 3415..3423, }, ), tooltip: "", @@ -514,7 +514,7 @@ fn main() { file_id: FileId( 1, ), - range: 3418..3422, + range: 3447..3451, }, ), tooltip: "", diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 2c08c457b33..4b2c139f6f4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -16,7 +16,7 @@ use stdx::format_to; use syntax::{ algo, ast::{self, HasArgList}, - match_ast, AstNode, Direction, SyntaxToken, TextRange, TextSize, + match_ast, AstNode, Direction, SyntaxElementChildren, SyntaxToken, TextRange, TextSize, }; use crate::RootDatabase; @@ -102,6 +102,20 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio } return signature_help_for_record_lit(&sema, record, token); }, + ast::RecordPat(record) => { + let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token); + if cursor_outside { + continue; + } + return signature_help_for_record_pat(&sema, record, token); + }, + ast::TupleStructPat(tuple_pat) => { + let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token); + if cursor_outside { + continue; + } + return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token); + }, _ => (), } } @@ -346,11 +360,112 @@ fn signature_help_for_record_lit( record: ast::RecordExpr, token: SyntaxToken, ) -> Option<SignatureHelp> { - let active_parameter = record - .record_expr_field_list()? + signature_help_for_record_( + sema, + record.record_expr_field_list()?.syntax().children_with_tokens(), + &record.path()?, + record + .record_expr_field_list()? + .fields() + .filter_map(|field| sema.resolve_record_field(&field)) + .map(|(field, _, ty)| (field, ty)), + token, + ) +} + +fn signature_help_for_record_pat( + sema: &Semantics<'_, RootDatabase>, + record: ast::RecordPat, + token: SyntaxToken, +) -> Option<SignatureHelp> { + signature_help_for_record_( + sema, + record.record_pat_field_list()?.syntax().children_with_tokens(), + &record.path()?, + record + .record_pat_field_list()? + .fields() + .filter_map(|field| sema.resolve_record_pat_field(&field)), + token, + ) +} + +fn signature_help_for_tuple_struct_pat( + sema: &Semantics<'_, RootDatabase>, + pat: ast::TupleStructPat, + token: SyntaxToken, +) -> Option<SignatureHelp> { + let rest_pat = pat.fields().find(|it| matches!(it, ast::Pat::RestPat(_))); + let is_left_of_rest_pat = + rest_pat.map_or(true, |it| token.text_range().start() < it.syntax().text_range().end()); + + let mut res = SignatureHelp { + doc: None, + signature: String::new(), + parameters: vec![], + active_parameter: None, + }; + + let db = sema.db; + let path_res = sema.resolve_path(&pat.path()?)?; + let fields: Vec<_> = if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { + let en = variant.parent_enum(db); + + res.doc = en.docs(db).map(|it| it.into()); + format_to!(res.signature, "enum {}::{} (", en.name(db), variant.name(db)); + variant.fields(db) + } else { + let adt = match path_res { + PathResolution::SelfType(imp) => imp.self_ty(db).as_adt()?, + PathResolution::Def(ModuleDef::Adt(adt)) => adt, + _ => return None, + }; + + match adt { + hir::Adt::Struct(it) => { + res.doc = it.docs(db).map(|it| it.into()); + format_to!(res.signature, "struct {} (", it.name(db)); + it.fields(db) + } + _ => return None, + } + }; + let commas = pat .syntax() .children_with_tokens() .filter_map(syntax::NodeOrToken::into_token) + .filter(|t| t.kind() == syntax::T![,]); + res.active_parameter = Some(if is_left_of_rest_pat { + commas.take_while(|t| t.text_range().start() <= token.text_range().start()).count() + } else { + let n_commas = commas + .collect::<Vec<_>>() + .into_iter() + .rev() + .take_while(|t| t.text_range().start() > token.text_range().start()) + .count(); + fields.len().saturating_sub(1).saturating_sub(n_commas) + }); + + let mut buf = String::new(); + for ty in fields.into_iter().map(|it| it.ty(db)) { + format_to!(buf, "{}", ty.display_truncated(db, Some(20))); + res.push_call_param(&buf); + buf.clear(); + } + res.signature.push_str(")"); + Some(res) +} + +fn signature_help_for_record_( + sema: &Semantics<'_, RootDatabase>, + field_list_children: SyntaxElementChildren, + path: &ast::Path, + fields2: impl Iterator<Item = (hir::Field, hir::Type)>, + token: SyntaxToken, +) -> Option<SignatureHelp> { + let active_parameter = field_list_children + .filter_map(syntax::NodeOrToken::into_token) .filter(|t| t.kind() == syntax::T![,]) .take_while(|t| t.text_range().start() <= token.text_range().start()) .count(); @@ -365,7 +480,7 @@ fn signature_help_for_record_lit( let fields; let db = sema.db; - let path_res = sema.resolve_path(&record.path()?)?; + let path_res = sema.resolve_path(path)?; if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { fields = variant.fields(db); let en = variant.parent_enum(db); @@ -397,8 +512,7 @@ fn signature_help_for_record_lit( let mut fields = fields.into_iter().map(|field| (field.name(db), Some(field))).collect::<FxIndexMap<_, _>>(); let mut buf = String::new(); - for field in record.record_expr_field_list()?.fields() { - let Some((field, _, ty)) = sema.resolve_record_field(&field) else { continue }; + for (field, ty) in fields2 { let name = field.name(db); format_to!(buf, "{name}: {}", ty.display_truncated(db, Some(20))); res.push_record_field(&buf); @@ -439,6 +553,7 @@ mod tests { (database, FilePosition { file_id, offset }) } + #[track_caller] fn check(ra_fixture: &str, expect: Expect) { let fixture = format!( r#" @@ -891,6 +1006,119 @@ fn main() { } #[test] + fn tuple_struct_pat() { + check( + r#" +/// A cool tuple struct +struct S(u32, i32); +fn main() { + let S(0, $0); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32) + --- ^^^ + "#]], + ); + } + + #[test] + fn tuple_struct_pat_rest() { + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16); +fn main() { + let S(0, .., $0); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16) + --- --- --- ^^^ + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16, u8); +fn main() { + let S(0, .., $0, 0); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16, u8) + --- --- --- ^^^ -- + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16); +fn main() { + let S($0, .., 1); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16) + ^^^ --- --- --- + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16, u8); +fn main() { + let S(1, .., 1, $0, 2); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16, u8) + --- --- --- ^^^ -- + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16); +fn main() { + let S(1, $0.., 1); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16) + --- ^^^ --- --- + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16); +fn main() { + let S(1, ..$0, 1); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16) + --- ^^^ --- --- + "#]], + ); + } + + #[test] fn generic_struct() { check( r#" @@ -1551,6 +1779,29 @@ impl S { } #[test] + fn record_pat() { + check( + r#" +struct Strukt<T, U = ()> { + t: T, + u: U, + unit: (), +} +fn f() { + let Strukt { + u: 0, + $0 + } +} +"#, + expect![[r#" + struct Strukt { u: i32, t: T, unit: () } + ------ ^^^^ -------- + "#]], + ); + } + + #[test] fn test_enum_in_nested_method_in_lambda() { check( r#" diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs index abcefffa23f..5f4977886f6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs @@ -431,14 +431,15 @@ fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker { fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) { while !p.at(EOF) && !p.at(ket) { - if !p.at_ts(PAT_TOP_FIRST) { - p.error("expected a pattern"); - break; - } - pattern_top(p); - if !p.at(ket) { - p.expect(T![,]); + if !p.at(T![,]) { + if p.at_ts(PAT_TOP_FIRST) { + p.error(format!("expected {:?}, got {:?}", T![,], p.current())); + } else { + break; + } + } else { + p.bump(T![,]); } } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs index 6df1273edd6..4e5d640f175 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs @@ -429,8 +429,9 @@ impl WorkspaceBuildScripts { for p in rustc.packages() { let package = &rustc[p]; if package.targets.iter().any(|&it| rustc[it].is_proc_macro) { - if let Some((_, path)) = - proc_macro_dylibs.iter().find(|(name, _)| *name == package.name) + if let Some((_, path)) = proc_macro_dylibs + .iter() + .find(|(name, _)| *name.trim_start_matches("lib") == package.name) { bs.outputs[p].proc_macro_dylib_path = Some(path.clone()); } diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 732adc50b50..01162b1a8ba 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -50,7 +50,7 @@ impl ops::Index<Target> for CargoWorkspace { /// Describes how to set the rustc source directory. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum RustcSource { +pub enum RustLibSource { /// Explicit path for the rustc source directory. Path(AbsPathBuf), /// Try to automatically detect where the rustc source directory is. @@ -95,10 +95,10 @@ pub struct CargoConfig { /// rustc target pub target: Option<String>, /// Sysroot loading behavior - pub sysroot: Option<RustcSource>, + pub sysroot: Option<RustLibSource>, pub sysroot_src: Option<AbsPathBuf>, /// rustc private crate source - pub rustc_source: Option<RustcSource>, + pub rustc_source: Option<RustLibSource>, /// crates to disable `#[cfg(test)]` on pub unset_test_crates: UnsetTestCrates, /// Invoke `cargo check` through the RUSTC_WRAPPER. diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index 9b6a71db811..70cb71ae3bd 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -44,7 +44,7 @@ pub use crate::{ build_scripts::WorkspaceBuildScripts, cargo_workspace::{ CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency, - RustcSource, Target, TargetData, TargetKind, UnsetTestCrates, + RustLibSource, Target, TargetData, TargetKind, UnsetTestCrates, }, manifest_path::ManifestPath, project_json::{ProjectJson, ProjectJsonData}, diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 749eee531ee..3754accbb03 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -24,8 +24,8 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr let project_workspace = ProjectWorkspace::Cargo { cargo: cargo_workspace, build_scripts: WorkspaceBuildScripts::default(), - sysroot: None, - rustc: None, + sysroot: Err(None), + rustc: Err(None), rustc_cfg: Vec::new(), cfg_overrides, toolchain: None, @@ -37,7 +37,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr fn load_rust_project(file: &str) -> CrateGraph { let data = get_test_json_file(file); let project = rooted_project_json(data); - let sysroot = Some(get_fake_sysroot()); + let sysroot = Ok(get_fake_sysroot()); let project_workspace = ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new() }; to_crate_graph(project_workspace) } diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index faa6816fdc2..d1e53e12eeb 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -17,7 +17,7 @@ use stdx::{always, hash::NoHashHashMap}; use crate::{ build_scripts::BuildScriptOutput, - cargo_workspace::{DepKind, PackageData, RustcSource}, + cargo_workspace::{DepKind, PackageData, RustLibSource}, cfg_flag::CfgFlag, rustc_cfg, sysroot::SysrootCrate, @@ -69,8 +69,8 @@ pub enum ProjectWorkspace { Cargo { cargo: CargoWorkspace, build_scripts: WorkspaceBuildScripts, - sysroot: Option<Sysroot>, - rustc: Option<(CargoWorkspace, WorkspaceBuildScripts)>, + sysroot: Result<Sysroot, Option<String>>, + rustc: Result<(CargoWorkspace, WorkspaceBuildScripts), Option<String>>, /// Holds cfg flags for the current target. We get those by running /// `rustc --print cfg`. /// @@ -82,7 +82,7 @@ pub enum ProjectWorkspace { target_layout: Result<String, String>, }, /// Project workspace was manually specified using a `rust-project.json` file. - Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, + Json { project: ProjectJson, sysroot: Result<Sysroot, Option<String>>, rustc_cfg: Vec<CfgFlag> }, // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning. // That's not the end user experience we should strive for. // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working. @@ -93,7 +93,11 @@ pub enum ProjectWorkspace { // // /// Project with a set of disjoint files, not belonging to any particular workspace. /// Backed by basic sysroot crates for basic completion and highlighting. - DetachedFiles { files: Vec<AbsPathBuf>, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, + DetachedFiles { + files: Vec<AbsPathBuf>, + sysroot: Result<Sysroot, Option<String>>, + rustc_cfg: Vec<CfgFlag>, + }, } impl fmt::Debug for ProjectWorkspace { @@ -113,7 +117,7 @@ impl fmt::Debug for ProjectWorkspace { .debug_struct("Cargo") .field("root", &cargo.workspace_root().file_name()) .field("n_packages", &cargo.packages().len()) - .field("sysroot", &sysroot.is_some()) + .field("sysroot", &sysroot.is_ok()) .field( "n_rustc_compiler_crates", &rustc.as_ref().map_or(0, |(rc, _)| rc.packages().len()), @@ -126,7 +130,7 @@ impl fmt::Debug for ProjectWorkspace { ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { let mut debug_struct = f.debug_struct("Json"); debug_struct.field("n_crates", &project.n_crates()); - if let Some(sysroot) = sysroot { + if let Ok(sysroot) = sysroot { debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); } debug_struct.field("n_rustc_cfg", &rustc_cfg.len()); @@ -135,7 +139,7 @@ impl fmt::Debug for ProjectWorkspace { ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f .debug_struct("DetachedFiles") .field("n_files", &files.len()) - .field("sysroot", &sysroot.is_some()) + .field("sysroot", &sysroot.is_ok()) .field("n_rustc_cfg", &rustc_cfg.len()) .finish(), } @@ -191,93 +195,81 @@ impl ProjectWorkspace { let cargo = CargoWorkspace::new(meta); let sysroot = match (&config.sysroot, &config.sysroot_src) { - (Some(RustcSource::Path(path)), None) => { - match Sysroot::with_sysroot_dir(path.clone()) { - Ok(it) => Some(it), - Err(e) => { - tracing::error!(%e, "Failed to find sysroot at {}.", path.display()); - None - } - } + (Some(RustLibSource::Path(path)), None) => { + Sysroot::with_sysroot_dir(path.clone()).map_err(|e| { + Some(format!("Failed to find sysroot at {}:{e}", path.display())) + }) } - (Some(RustcSource::Discover), None) => { - match Sysroot::discover(cargo_toml.parent(), &config.extra_env) { - Ok(it) => Some(it), - Err(e) => { - tracing::error!( - %e, - "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?", - cargo_toml.display() - ); - None - } - } + (Some(RustLibSource::Discover), None) => { + Sysroot::discover(cargo_toml.parent(), &config.extra_env).map_err(|e| { + Some(format!("Failed to find sysroot for Cargo.toml file {}. Is rust-src installed? {e}", cargo_toml.display())) + }) } - (Some(RustcSource::Path(sysroot)), Some(sysroot_src)) => { - Some(Sysroot::load(sysroot.clone(), sysroot_src.clone())) + (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => { + Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone())) } - (Some(RustcSource::Discover), Some(sysroot_src)) => { - match Sysroot::discover_with_src_override( + (Some(RustLibSource::Discover), Some(sysroot_src)) => { + Sysroot::discover_with_src_override( cargo_toml.parent(), &config.extra_env, sysroot_src.clone(), - ) { - Ok(it) => Some(it), - Err(e) => { - tracing::error!( - %e, - "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?", - cargo_toml.display() - ); - None - } - } + ).map_err(|e| { + Some(format!("Failed to find sysroot for Cargo.toml file {}. Is rust-src installed? {e}", cargo_toml.display())) + }) } - (None, _) => None, + (None, _) => Err(None), }; - if let Some(sysroot) = &sysroot { + if let Ok(sysroot) = &sysroot { tracing::info!(workspace = %cargo_toml.display(), src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot"); } let rustc_dir = match &config.rustc_source { - Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(), - Some(RustcSource::Discover) => { - sysroot.as_ref().and_then(Sysroot::discover_rustc) + Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone()) + .map_err(|p| { + Some(format!("rustc source path is not absolute: {}", p.display())) + }), + Some(RustLibSource::Discover) => { + sysroot.as_ref().ok().and_then(Sysroot::discover_rustc).ok_or_else(|| { + Some(format!("Failed to discover rustc source for sysroot.")) + }) } - None => None, + None => Err(None), }; - let rustc = match rustc_dir { - Some(rustc_dir) => { - tracing::info!(workspace = %cargo_toml.display(), rustc_dir = %rustc_dir.display(), "Using rustc source"); - match CargoWorkspace::fetch_metadata( - &rustc_dir, - cargo_toml.parent(), - config, - progress, - ) { - Ok(meta) => { - let workspace = CargoWorkspace::new(meta); - let buildscripts = WorkspaceBuildScripts::rustc_crates( - &workspace, - cargo_toml.parent(), - &config.extra_env, - ); - Some((workspace, buildscripts)) - } - Err(e) => { - tracing::error!( - %e, - "Failed to read Cargo metadata from rustc source at {}", - rustc_dir.display() - ); - None - } + let rustc = rustc_dir.and_then(|rustc_dir| { + tracing::info!(workspace = %cargo_toml.display(), rustc_dir = %rustc_dir.display(), "Using rustc source"); + match CargoWorkspace::fetch_metadata( + &rustc_dir, + cargo_toml.parent(), + &CargoConfig { + features: crate::CargoFeatures::default(), + ..config.clone() + }, + progress, + ) { + Ok(meta) => { + let workspace = CargoWorkspace::new(meta); + let buildscripts = WorkspaceBuildScripts::rustc_crates( + &workspace, + cargo_toml.parent(), + &config.extra_env, + ); + Ok((workspace, buildscripts)) + } + Err(e) => { + tracing::error!( + %e, + "Failed to read Cargo metadata from rustc source at {}", + rustc_dir.display() + ); + Err(Some(format!( + "Failed to read Cargo metadata from rustc source at {}: {e}", + rustc_dir.display()) + )) } } - None => None, - }; + }); let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env); @@ -313,12 +305,12 @@ impl ProjectWorkspace { extra_env: &FxHashMap<String, String>, ) -> ProjectWorkspace { let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { - (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)), + (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src)), (Some(sysroot), None) => { // assume sysroot is structured like rustup's and guess `sysroot_src` let sysroot_src = sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); - Some(Sysroot::load(sysroot, sysroot_src)) + Ok(Sysroot::load(sysroot, sysroot_src)) } (None, Some(sysroot_src)) => { // assume sysroot is structured like rustup's and guess `sysroot` @@ -326,11 +318,11 @@ impl ProjectWorkspace { for _ in 0..5 { sysroot.pop(); } - Some(Sysroot::load(sysroot, sysroot_src)) + Ok(Sysroot::load(sysroot, sysroot_src)) } - (None, None) => None, + (None, None) => Err(None), }; - if let Some(sysroot) = &sysroot { + if let Ok(sysroot) = &sysroot { tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot"); } @@ -343,33 +335,23 @@ impl ProjectWorkspace { config: &CargoConfig, ) -> Result<ProjectWorkspace> { let sysroot = match &config.sysroot { - Some(RustcSource::Path(path)) => match Sysroot::with_sysroot_dir(path.clone()) { - Ok(it) => Some(it), - Err(e) => { - tracing::error!(%e, "Failed to find sysroot at {}.", path.display()); - None - } - }, - Some(RustcSource::Discover) => { + Some(RustLibSource::Path(path)) => Sysroot::with_sysroot_dir(path.clone()) + .map_err(|e| Some(format!("Failed to find sysroot at {}:{e}", path.display()))), + Some(RustLibSource::Discover) => { let dir = &detached_files .first() .and_then(|it| it.parent()) .ok_or_else(|| format_err!("No detached files to load"))?; - match Sysroot::discover(dir, &config.extra_env) { - Ok(it) => Some(it), - Err(e) => { - tracing::error!( - %e, - "Failed to find sysroot for {}. Is rust-src installed?", - dir.display() - ); - None - } - } + Sysroot::discover(dir, &config.extra_env).map_err(|e| { + Some(format!( + "Failed to find sysroot for {}. Is rust-src installed? {e}", + dir.display() + )) + }) } - None => None, + None => Err(None), }; - if let Some(sysroot) = &sysroot { + if let Ok(sysroot) = &sysroot { tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot"); } let rustc_cfg = rustc_cfg::get(None, None, &Default::default()); @@ -450,10 +432,18 @@ impl ProjectWorkspace { } } + pub fn workspace_definition_path(&self) -> Option<&AbsPath> { + match self { + ProjectWorkspace::Cargo { cargo, .. } => Some(cargo.workspace_root()), + ProjectWorkspace::Json { project, .. } => Some(project.path()), + ProjectWorkspace::DetachedFiles { .. } => None, + } + } + pub fn find_sysroot_proc_macro_srv(&self) -> Option<AbsPathBuf> { match self { - ProjectWorkspace::Cargo { sysroot: Some(sysroot), .. } - | ProjectWorkspace::Json { sysroot: Some(sysroot), .. } => { + ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. } + | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. } => { let standalone_server_name = format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); ["libexec", "lib"] @@ -469,7 +459,7 @@ impl ProjectWorkspace { /// The return type contains the path and whether or not /// the root is a member of the current workspace pub fn to_roots(&self) -> Vec<PackageRoot> { - let mk_sysroot = |sysroot: Option<&Sysroot>, project_root: Option<&AbsPath>| { + let mk_sysroot = |sysroot: Result<&Sysroot, _>, project_root: Option<&AbsPath>| { sysroot.map(|sysroot| PackageRoot { // mark the sysroot as mutable if it is located inside of the project is_local: project_root @@ -592,7 +582,7 @@ impl ProjectWorkspace { load_proc_macro, load, project, - sysroot.as_ref(), + sysroot.as_ref().ok(), extra_env, Err("rust-project.json projects have no target layout set".into()), ), @@ -608,9 +598,9 @@ impl ProjectWorkspace { } => cargo_to_crate_graph( load_proc_macro, load, - rustc, + rustc.as_ref().ok(), cargo, - sysroot.as_ref(), + sysroot.as_ref().ok(), rustc_cfg.clone(), cfg_overrides, build_scripts, @@ -624,7 +614,7 @@ impl ProjectWorkspace { rustc_cfg.clone(), load, files, - sysroot, + sysroot.as_ref().ok(), Err("detached file projects have no target layout set".into()), ) } @@ -786,7 +776,7 @@ fn project_json_to_crate_graph( fn cargo_to_crate_graph( load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, - rustc: &Option<(CargoWorkspace, WorkspaceBuildScripts)>, + rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>, cargo: &CargoWorkspace, sysroot: Option<&Sysroot>, rustc_cfg: Vec<CfgFlag>, @@ -932,7 +922,7 @@ fn cargo_to_crate_graph( if has_private { // If the user provided a path to rustc sources, we add all the rustc_private crates // and create dependencies on them for the crates which opt-in to that - if let Some((rustc_workspace, build_scripts)) = rustc { + if let Some((rustc_workspace, rustc_build_scripts)) = rustc { handle_rustc_crates( &mut crate_graph, &mut pkg_to_lib_crate, @@ -945,7 +935,13 @@ fn cargo_to_crate_graph( &pkg_crates, &cfg_options, override_cfg, - build_scripts, + if rustc_workspace.workspace_root() == cargo.workspace_root() { + // the rustc workspace does not use the installed toolchain's proc-macro server + // so we need to make sure we don't use the pre compiled proc-macros there either + build_scripts + } else { + rustc_build_scripts + }, target_layout, ); } @@ -957,7 +953,7 @@ fn detached_files_to_crate_graph( rustc_cfg: Vec<CfgFlag>, load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, detached_files: &[AbsPathBuf], - sysroot: &Option<Sysroot>, + sysroot: Option<&Sysroot>, target_layout: TargetLayoutLoadResult, ) -> CrateGraph { let _p = profile::span("detached_files_to_crate_graph"); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index e8c10927d62..6ce1de5d32b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -7,7 +7,7 @@ use std::{ }; use hir::{ - db::{AstDatabase, DefDatabase, HirDatabase}, + db::{DefDatabase, ExpandDatabase, HirDatabase}, AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef, }; use hir_def::{ @@ -24,7 +24,7 @@ use ide_db::base_db::{ use itertools::Itertools; use oorandom::Rand32; use profile::{Bytes, StopWatch}; -use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustcSource}; +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use rayon::prelude::*; use rustc_hash::FxHashSet; use stdx::format_to; @@ -57,7 +57,7 @@ impl flags::AnalysisStats { let mut cargo_config = CargoConfig::default(); cargo_config.sysroot = match self.no_sysroot { true => None, - false => Some(RustcSource::Discover), + false => Some(RustLibSource::Discover), }; let no_progress = &|_| (); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index 0721d486ef1..4006d023def 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -1,7 +1,7 @@ //! Analyze all modules in a project for diagnostics. Exits with a non-zero //! status code if any errors are found. -use project_model::{CargoConfig, RustcSource}; +use project_model::{CargoConfig, RustLibSource}; use rustc_hash::FxHashSet; use hir::{db::HirDatabase, Crate, Module}; @@ -16,7 +16,7 @@ use crate::cli::{ impl flags::Diagnostics { pub fn run(self) -> anyhow::Result<()> { let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustcSource::Discover); + cargo_config.sysroot = Some(RustLibSource::Discover); let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: !self.disable_build_scripts, with_proc_macro_server: ProcMacroServerChoice::Sysroot, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs index 9b5451496c6..7f5d0844967 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs @@ -13,7 +13,7 @@ use ide_db::LineIndexDatabase; use ide_db::base_db::salsa::{self, ParallelDatabase}; use ide_db::line_index::WideEncoding; use lsp_types::{self, lsif}; -use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustcSource}; +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use vfs::{AbsPathBuf, Vfs}; use crate::cli::load_cargo::ProcMacroServerChoice; @@ -290,7 +290,7 @@ impl flags::Lsif { eprintln!("Generating LSIF started..."); let now = Instant::now(); let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustcSource::Discover); + cargo_config.sysroot = Some(RustLibSource::Discover); let no_progress = &|_| (); let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index df5c26cf77a..3e5e40750e9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -15,7 +15,7 @@ use ide::{ TokenStaticData, }; use ide_db::LineIndexDatabase; -use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustcSource}; +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use scip::types as scip_types; use std::env; @@ -30,7 +30,7 @@ impl flags::Scip { eprintln!("Generating SCIP start..."); let now = Instant::now(); let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustcSource::Discover); + cargo_config.sysroot = Some(RustLibSource::Discover); let no_progress = &|s| (eprintln!("rust-analyzer: Loading {s}")); let load_cargo_config = LoadCargoConfig { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs index 35a874f8920..82a769347df 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs @@ -1,7 +1,7 @@ //! Applies structured search replace rules from the command line. use ide_ssr::MatchFinder; -use project_model::{CargoConfig, RustcSource}; +use project_model::{CargoConfig, RustLibSource}; use crate::cli::{ flags, @@ -13,7 +13,7 @@ impl flags::Ssr { pub fn run(self) -> Result<()> { use ide_db::base_db::SourceDatabaseExt; let mut cargo_config = CargoConfig::default(); - cargo_config.sysroot = Some(RustcSource::Discover); + cargo_config.sysroot = Some(RustLibSource::Discover); let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 75233dbb2ab..c35cce103fa 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -22,7 +22,7 @@ use ide_db::{ use itertools::Itertools; use lsp_types::{ClientCapabilities, MarkupKind}; use project_model::{ - CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource, + CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource, UnsetTestCrates, }; use rustc_hash::{FxHashMap, FxHashSet}; @@ -272,7 +272,6 @@ config_data! { /// The warnings will be indicated by a blue squiggly underline in code /// and a blue icon in the `Problems Panel`. diagnostics_warningsAsInfo: Vec<String> = "[]", - /// These directories will be ignored by rust-analyzer. They are /// relative to the workspace root, and globs are not supported. You may /// also need to add the folders to Code's `files.watcherExclude`. @@ -895,6 +894,15 @@ impl Config { } } + pub fn add_linked_projects(&mut self, linked_projects: Vec<ProjectJsonData>) { + let mut linked_projects = linked_projects + .into_iter() + .map(ManifestOrProjectJson::ProjectJson) + .collect::<Vec<ManifestOrProjectJson>>(); + + self.data.linkedProjects.append(&mut linked_projects); + } + pub fn did_save_text_document_dynamic_registration(&self) -> bool { let caps = try_or_def!(self.caps.text_document.as_ref()?.synchronization.clone()?); caps.did_save == Some(true) && caps.dynamic_registration == Some(true) @@ -1129,16 +1137,16 @@ impl Config { pub fn cargo(&self) -> CargoConfig { let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| { if rustc_src == "discover" { - RustcSource::Discover + RustLibSource::Discover } else { - RustcSource::Path(self.root_path.join(rustc_src)) + RustLibSource::Path(self.root_path.join(rustc_src)) } }); let sysroot = self.data.cargo_sysroot.as_ref().map(|sysroot| { if sysroot == "discover" { - RustcSource::Discover + RustLibSource::Discover } else { - RustcSource::Path(self.root_path.join(sysroot)) + RustLibSource::Path(self.root_path.join(sysroot)) } }); let sysroot_src = diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs index 715804449a0..313bb2ec8df 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs @@ -88,6 +88,42 @@ impl<'a> RequestDispatcher<'a> { } /// Dispatches the request onto thread pool + pub(crate) fn on_no_retry<R>( + &mut self, + f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>, + ) -> &mut Self + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, + R::Result: Serialize, + { + let (req, params, panic_context) = match self.parse::<R>() { + Some(it) => it, + None => return self, + }; + + self.global_state.task_pool.handle.spawn({ + let world = self.global_state.snapshot(); + move || { + let result = panic::catch_unwind(move || { + let _pctx = stdx::panic_context::enter(panic_context); + f(world, params) + }); + match thread_result_to_response::<R>(req.id.clone(), result) { + Ok(response) => Task::Response(response), + Err(_) => Task::Response(lsp_server::Response::new_err( + req.id, + lsp_server::ErrorCode::ContentModified as i32, + "content modified".to_string(), + )), + } + } + }); + + self + } + + /// Dispatches the request onto thread pool pub(crate) fn on<R>( &mut self, f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs index 32ac9a42dec..2fca2ab851d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs @@ -29,7 +29,7 @@ use project_model::{ManifestPath, ProjectWorkspace, TargetKind}; use serde_json::json; use stdx::{format_to, never}; use syntax::{algo, ast, AstNode, TextRange, TextSize}; -use vfs::AbsPathBuf; +use vfs::{AbsPath, AbsPathBuf}; use crate::{ cargo_target_spec::CargoTargetSpec, @@ -46,6 +46,7 @@ use crate::{ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> { state.proc_macro_clients.clear(); state.proc_macro_changed = false; + state.fetch_workspaces_queue.request_op("reload workspace request".to_string()); state.fetch_build_data_queue.request_op("reload workspace request".to_string()); Ok(()) @@ -84,6 +85,15 @@ pub(crate) fn handle_analyzer_status( snap.workspaces.len(), if snap.workspaces.len() == 1 { "" } else { "s" } ); + + format_to!( + buf, + "Workspace root folders: {:?}", + snap.workspaces + .iter() + .flat_map(|ws| ws.workspace_definition_path()) + .collect::<Vec<&AbsPath>>() + ); } buf.push_str("\nAnalysis:\n"); buf.push_str( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs index 30f1c53c198..12e5caf2cc9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs @@ -36,11 +36,41 @@ impl Progress { } impl GlobalState { - pub(crate) fn show_message(&mut self, typ: lsp_types::MessageType, message: String) { - let message = message; - self.send_notification::<lsp_types::notification::ShowMessage>( - lsp_types::ShowMessageParams { typ, message }, - ) + pub(crate) fn show_message( + &mut self, + typ: lsp_types::MessageType, + message: String, + show_open_log_button: bool, + ) { + match self.config.open_server_logs() && show_open_log_button { + true => self.send_request::<lsp_types::request::ShowMessageRequest>( + lsp_types::ShowMessageRequestParams { + typ, + message, + actions: Some(vec![lsp_types::MessageActionItem { + title: "Open server logs".to_owned(), + properties: Default::default(), + }]), + }, + |this, resp| { + let lsp_server::Response { error: None, result: Some(result), .. } = resp + else { return }; + if let Ok(Some(_item)) = crate::from_json::< + <lsp_types::request::ShowMessageRequest as lsp_types::request::Request>::Result, + >( + lsp_types::request::ShowMessageRequest::METHOD, &result + ) { + this.send_notification::<lsp_ext::OpenServerLogs>(()); + } + }, + ), + false => self.send_notification::<lsp_types::notification::ShowMessage>( + lsp_types::ShowMessageParams { + typ, + message, + }, + ), + } } /// Sends a notification to the client containing the error `message`. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index dd0804b4398..67a54cde68c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -406,9 +406,19 @@ impl GlobalState { if self.config.server_status_notification() { self.send_notification::<lsp_ext::ServerStatusNotification>(status); - } else if let (lsp_ext::Health::Error, Some(message)) = (status.health, &status.message) - { - self.show_and_log_error(message.clone(), None); + } else if let (health, Some(message)) = (status.health, &status.message) { + let open_log_button = tracing::enabled!(tracing::Level::ERROR) + && (self.fetch_build_data_error().is_err() + || self.fetch_workspace_error().is_err()); + self.show_message( + match health { + lsp_ext::Health::Ok => lsp_types::MessageType::INFO, + lsp_ext::Health::Warning => lsp_types::MessageType::WARNING, + lsp_ext::Health::Error => lsp_types::MessageType::ERROR, + }, + message.clone(), + open_log_button, + ); } } } @@ -653,7 +663,7 @@ impl GlobalState { .on::<lsp_types::request::GotoDeclaration>(handlers::handle_goto_declaration) .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation) .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition) - .on::<lsp_types::request::InlayHintRequest>(handlers::handle_inlay_hints) + .on_no_retry::<lsp_types::request::InlayHintRequest>(handlers::handle_inlay_hints) .on::<lsp_types::request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve) .on::<lsp_types::request::Completion>(handlers::handle_completion) .on::<lsp_types::request::ResolveCompletionItem>(handlers::handle_completion_resolve) @@ -919,6 +929,7 @@ impl GlobalState { this.show_message( lsp_types::MessageType::WARNING, error.to_string(), + false, ); } this.update_configuration(config); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 28d37f5685a..1a6e1af2eb7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -90,38 +90,55 @@ impl GlobalState { quiescent: self.is_quiescent(), message: None, }; + let mut message = String::new(); if self.proc_macro_changed { status.health = lsp_ext::Health::Warning; - status.message = - Some("Reload required due to source changes of a procedural macro.".into()) + message.push_str("Reload required due to source changes of a procedural macro.\n\n"); } if let Err(_) = self.fetch_build_data_error() { status.health = lsp_ext::Health::Warning; - status.message = - Some("Failed to run build scripts of some packages, check the logs.".to_string()); + message.push_str("Failed to run build scripts of some packages.\n\n"); } if !self.config.cargo_autoreload() && self.is_quiescent() && self.fetch_workspaces_queue.op_requested() { status.health = lsp_ext::Health::Warning; - status.message = Some("Workspace reload required".to_string()) + message.push_str("Auto-reloading is disabled and the workspace has changed, a manual workspace reload is required.\n\n"); } - - if let Err(_) = self.fetch_workspace_error() { - status.health = lsp_ext::Health::Error; - status.message = Some("Failed to load workspaces".to_string()) - } - if self.config.linked_projects().is_empty() && self.config.detached_files().is_empty() && self.config.notifications().cargo_toml_not_found { status.health = lsp_ext::Health::Warning; - status.message = Some("Failed to discover workspace".to_string()) + message.push_str("Failed to discover workspace.\n\n"); + } + + for ws in self.workspaces.iter() { + let (ProjectWorkspace::Cargo { sysroot, .. } + | ProjectWorkspace::Json { sysroot, .. } + | ProjectWorkspace::DetachedFiles { sysroot, .. }) = ws; + if let Err(Some(e)) = sysroot { + status.health = lsp_ext::Health::Warning; + message.push_str(e); + message.push_str("\n\n"); + } + if let ProjectWorkspace::Cargo { rustc: Err(Some(e)), .. } = ws { + status.health = lsp_ext::Health::Warning; + message.push_str(e); + message.push_str("\n\n"); + } } + if let Err(_) = self.fetch_workspace_error() { + status.health = lsp_ext::Health::Error; + message.push_str("Failed to load workspaces.\n\n"); + } + + if !message.is_empty() { + status.message = Some(message.trim_end().to_owned()); + } status } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs index db66d08a73b..c43d0830b9e 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs @@ -48,23 +48,30 @@ impl From<ast::IfExpr> for ElseBranch { } impl ast::IfExpr { - pub fn then_branch(&self) -> Option<ast::BlockExpr> { - self.children_after_condition().next() + pub fn condition(&self) -> Option<ast::Expr> { + // If the condition is a BlockExpr, check if the then body is missing. + // If it is assume the condition is the expression that is missing instead. + let mut exprs = support::children(self.syntax()); + let first = exprs.next(); + match first { + Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first), + first => first, + } } - pub fn else_branch(&self) -> Option<ElseBranch> { - let res = match self.children_after_condition().nth(1) { - Some(block) => ElseBranch::Block(block), - None => { - let elif = self.children_after_condition().next()?; - ElseBranch::IfExpr(elif) - } - }; - Some(res) + pub fn then_branch(&self) -> Option<ast::BlockExpr> { + match support::children(self.syntax()).nth(1)? { + ast::Expr::BlockExpr(block) => Some(block), + _ => None, + } } - fn children_after_condition<N: AstNode>(&self) -> impl Iterator<Item = N> { - self.syntax().children().skip(1).filter_map(N::cast) + pub fn else_branch(&self) -> Option<ElseBranch> { + match support::children(self.syntax()).nth(2)? { + ast::Expr::BlockExpr(block) => Some(ElseBranch::Block(block)), + ast::Expr::IfExpr(elif) => Some(ElseBranch::IfExpr(elif)), + _ => None, + } } } @@ -356,7 +363,15 @@ impl ast::BlockExpr { Some(it) => it, None => return true, }; - !matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR) + match parent.kind() { + FOR_EXPR | IF_EXPR => parent + .children() + .filter(|it| ast::Expr::can_cast(it.kind())) + .next() + .map_or(true, |it| it == *self.syntax()), + LET_ELSE | FN | WHILE_EXPR | LOOP_EXPR | CONST_BLOCK_PAT => false, + _ => true, + } } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 15bd5ab3c72..3308077da5b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -937,12 +937,6 @@ impl From<ast::Adt> for ast::Item { } } -impl ast::IfExpr { - pub fn condition(&self) -> Option<ast::Expr> { - support::child(&self.syntax) - } -} - impl ast::MatchGuard { pub fn condition(&self) -> Option<ast::Expr> { support::child(&self.syntax) diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 93ff76a040c..ca6de4061a4 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -44,6 +44,8 @@ //! try: infallible //! unsize: sized +#![rustc_coherence_is_core] + pub mod marker { // region:sized #[lang = "sized"] diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index a3b1a3107d0..c5eb08748bf 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -200,6 +200,11 @@ "category": "rust-analyzer" }, { + "command": "rust-analyzer.addProject", + "title": "Add current file's crate to workspace", + "category": "rust-analyzer" + }, + { "command": "rust-analyzer.reload", "title": "Restart server", "category": "rust-analyzer" @@ -428,6 +433,17 @@ "default": false, "type": "boolean" }, + "rust-analyzer.discoverProjectCommand": { + "markdownDescription": "Sets the command that rust-analyzer uses to generate `rust-project.json` files. This command should only be used\n if a build system like Buck or Bazel is also in use. The command must accept files as arguments and return \n a rust-project.json over stdout.", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + }, "$generated-start": {}, "rust-analyzer.assist.emitMustUse": { "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.", diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index 62980ca0464..565cb9c6432 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -6,7 +6,7 @@ import * as Is from "vscode-languageclient/lib/common/utils/is"; import { assert } from "./util"; import * as diagnostics from "./diagnostics"; import { WorkspaceEdit } from "vscode"; -import { Config, substituteVSCodeVariables } from "./config"; +import { Config, prepareVSCodeConfig } from "./config"; import { randomUUID } from "crypto"; export interface Env { @@ -95,7 +95,16 @@ export async function createClient( const resp = await next(params, token); if (resp && Array.isArray(resp)) { return resp.map((val) => { - return substituteVSCodeVariables(val); + return prepareVSCodeConfig(val, (key, cfg) => { + // we only want to set discovered workspaces on the right key + // and if a workspace has been discovered. + if ( + key === "linkedProjects" && + config.discoveredWorkspaces.length > 0 + ) { + cfg[key] = config.discoveredWorkspaces; + } + }); }); } else { return resp; diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index f4a4579a92c..8a953577e99 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -3,7 +3,7 @@ import * as lc from "vscode-languageclient"; import * as ra from "./lsp_ext"; import * as path from "path"; -import { Ctx, Cmd, CtxInit } from "./ctx"; +import { Ctx, Cmd, CtxInit, discoverWorkspace } from "./ctx"; import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets"; import { spawnSync } from "child_process"; import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run"; @@ -749,6 +749,33 @@ export function reloadWorkspace(ctx: CtxInit): Cmd { return async () => ctx.client.sendRequest(ra.reloadWorkspace); } +export function addProject(ctx: CtxInit): Cmd { + return async () => { + const discoverProjectCommand = ctx.config.discoverProjectCommand; + if (!discoverProjectCommand) { + return; + } + + const workspaces: JsonProject[] = await Promise.all( + vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => { + const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument); + return discoverWorkspace(rustDocuments, discoverProjectCommand, { + cwd: folder.uri.fsPath, + }); + }) + ); + + ctx.addToDiscoveredWorkspaces(workspaces); + + // this is a workaround to avoid needing writing the `rust-project.json` into + // a workspace-level VS Code-specific settings folder. We'd like to keep the + // `rust-project.json` entirely in-memory. + await ctx.client?.sendNotification(lc.DidChangeConfigurationNotification.type, { + settings: "", + }); + }; +} + async function showReferencesImpl( client: LanguageClient | undefined, uri: string, diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 1faa0ad9106..da7c74c28ba 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -34,6 +34,7 @@ export class Config { constructor(ctx: vscode.ExtensionContext) { this.globalStorageUri = ctx.globalStorageUri; + this.discoveredWorkspaces = []; vscode.workspace.onDidChangeConfiguration( this.onDidChangeConfiguration, this, @@ -55,6 +56,8 @@ export class Config { log.info("Using configuration", Object.fromEntries(cfg)); } + public discoveredWorkspaces: JsonProject[]; + private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) { this.refreshLogging(); @@ -191,7 +194,7 @@ export class Config { * So this getter handles this quirk by not requiring the caller to use postfix `!` */ private get<T>(path: string): T | undefined { - return substituteVSCodeVariables(this.cfg.get<T>(path)); + return prepareVSCodeConfig(this.cfg.get<T>(path)); } get serverPath() { @@ -214,6 +217,10 @@ export class Config { return this.get<boolean>("trace.extension"); } + get discoverProjectCommand() { + return this.get<string[] | undefined>("discoverProjectCommand"); + } + get cargoRunner() { return this.get<string | undefined>("cargoRunner"); } @@ -280,18 +287,32 @@ export class Config { } } -export function substituteVSCodeVariables<T>(resp: T): T { +// the optional `cb?` parameter is meant to be used to add additional +// key/value pairs to the VS Code configuration. This needed for, e.g., +// including a `rust-project.json` into the `linkedProjects` key as part +// of the configuration/InitializationParams _without_ causing VS Code +// configuration to be written out to workspace-level settings. This is +// undesirable behavior because rust-project.json files can be tens of +// thousands of lines of JSON, most of which is not meant for humans +// to interact with. +export function prepareVSCodeConfig<T>( + resp: T, + cb?: (key: Extract<keyof T, string>, res: { [key: string]: any }) => void +): T { if (Is.string(resp)) { return substituteVSCodeVariableInString(resp) as T; } else if (resp && Is.array<any>(resp)) { return resp.map((val) => { - return substituteVSCodeVariables(val); + return prepareVSCodeConfig(val); }) as T; } else if (resp && typeof resp === "object") { const res: { [key: string]: any } = {}; for (const key in resp) { const val = resp[key]; - res[key] = substituteVSCodeVariables(val); + res[key] = prepareVSCodeConfig(val); + if (cb) { + cb(key, res); + } } return res as T; } diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 1708d47cee7..c2dca733df8 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -2,12 +2,20 @@ import * as vscode from "vscode"; import * as lc from "vscode-languageclient/node"; import * as ra from "./lsp_ext"; -import { Config, substituteVSCodeVariables } from "./config"; +import { Config, prepareVSCodeConfig } from "./config"; import { createClient } from "./client"; -import { isRustDocument, isRustEditor, LazyOutputChannel, log, RustEditor } from "./util"; +import { + executeDiscoverProject, + isRustDocument, + isRustEditor, + LazyOutputChannel, + log, + RustEditor, +} from "./util"; import { ServerStatusParams } from "./lsp_ext"; import { PersistentState } from "./persistent_state"; import { bootstrap } from "./bootstrap"; +import { ExecOptions } from "child_process"; // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if // only those are in use. We use "Empty" to represent these scenarios @@ -41,6 +49,17 @@ export function fetchWorkspace(): Workspace { : { kind: "Workspace Folder" }; } +export async function discoverWorkspace( + files: readonly vscode.TextDocument[], + command: string[], + options: ExecOptions +): Promise<JsonProject> { + const paths = files.map((f) => `"${f.uri.fsPath}"`).join(" "); + const joinedCommand = command.join(" "); + const data = await executeDiscoverProject(`${joinedCommand} ${paths}`, options); + return JSON.parse(data) as JsonProject; +} + export type CommandFactory = { enabled: (ctx: CtxInit) => Cmd; disabled?: (ctx: Ctx) => Cmd; @@ -52,7 +71,7 @@ export type CtxInit = Ctx & { export class Ctx { readonly statusBar: vscode.StatusBarItem; - readonly config: Config; + config: Config; readonly workspace: Workspace; private _client: lc.LanguageClient | undefined; @@ -169,7 +188,30 @@ export class Ctx { }; } - const initializationOptions = substituteVSCodeVariables(rawInitializationOptions); + const discoverProjectCommand = this.config.discoverProjectCommand; + if (discoverProjectCommand) { + const workspaces: JsonProject[] = await Promise.all( + vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => { + const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument); + return discoverWorkspace(rustDocuments, discoverProjectCommand, { + cwd: folder.uri.fsPath, + }); + }) + ); + + this.addToDiscoveredWorkspaces(workspaces); + } + + const initializationOptions = prepareVSCodeConfig( + rawInitializationOptions, + (key, obj) => { + // we only want to set discovered workspaces on the right key + // and if a workspace has been discovered. + if (key === "linkedProjects" && this.config.discoveredWorkspaces.length > 0) { + obj["linkedProjects"] = this.config.discoveredWorkspaces; + } + } + ); this._client = await createClient( this.traceOutputChannel, @@ -251,6 +293,17 @@ export class Ctx { return this._serverPath; } + addToDiscoveredWorkspaces(workspaces: JsonProject[]) { + for (const workspace of workspaces) { + const index = this.config.discoveredWorkspaces.indexOf(workspace); + if (~index) { + this.config.discoveredWorkspaces[index] = workspace; + } else { + this.config.discoveredWorkspaces.push(workspace); + } + } + } + private updateCommands(forceDisable?: "disable") { this.commandDisposables.forEach((disposable) => disposable.dispose()); this.commandDisposables = []; @@ -289,6 +342,7 @@ export class Ctx { statusBar.tooltip.appendText(status.message ?? "Ready"); statusBar.color = undefined; statusBar.backgroundColor = undefined; + statusBar.command = "rust-analyzer.stopServer"; break; case "warning": if (status.message) { @@ -298,6 +352,7 @@ export class Ctx { statusBar.backgroundColor = new vscode.ThemeColor( "statusBarItem.warningBackground" ); + statusBar.command = "rust-analyzer.openLogs"; icon = "$(warning) "; break; case "error": @@ -306,6 +361,7 @@ export class Ctx { } statusBar.color = new vscode.ThemeColor("statusBarItem.errorForeground"); statusBar.backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground"); + statusBar.command = "rust-analyzer.openLogs"; icon = "$(error) "; break; case "stopped": @@ -315,18 +371,19 @@ export class Ctx { ); statusBar.color = undefined; statusBar.backgroundColor = undefined; + statusBar.command = "rust-analyzer.startServer"; statusBar.text = `$(stop-circle) rust-analyzer`; return; } if (statusBar.tooltip.value) { statusBar.tooltip.appendText("\n\n"); } - statusBar.tooltip.appendMarkdown("[Stop server](command:rust-analyzer.stopServer)"); statusBar.tooltip.appendMarkdown( "\n\n[Reload Workspace](command:rust-analyzer.reloadWorkspace)" ); - statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)"); statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); + statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)"); + statusBar.tooltip.appendMarkdown("[Stop server](command:rust-analyzer.stopServer)"); if (!status.quiescent) icon = "$(sync~spin) "; statusBar.text = `${icon}rust-analyzer`; } diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts index 400cd207d41..872d7199b83 100644 --- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts +++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts @@ -43,6 +43,7 @@ export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, Te "rust-analyzer/relatedTests" ); export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace"); + export const runFlycheck = new lc.NotificationType<{ textDocument: lc.TextDocumentIdentifier | null; }>("rust-analyzer/runFlycheck"); diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 8a2412af849..d5de00561b1 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -153,6 +153,7 @@ function createCommands(): Record<string, CommandFactory> { memoryUsage: { enabled: commands.memoryUsage }, shuffleCrateGraph: { enabled: commands.shuffleCrateGraph }, reloadWorkspace: { enabled: commands.reloadWorkspace }, + addProject: { enabled: commands.addProject }, matchingBrace: { enabled: commands.matchingBrace }, joinLines: { enabled: commands.joinLines }, parentModule: { enabled: commands.parentModule }, diff --git a/src/tools/rust-analyzer/editors/code/src/rust_project.ts b/src/tools/rust-analyzer/editors/code/src/rust_project.ts new file mode 100644 index 00000000000..187a1a96c10 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/rust_project.ts @@ -0,0 +1,91 @@ +interface JsonProject { + /// Path to the directory with *source code* of + /// sysroot crates. + /// + /// It should point to the directory where std, + /// core, and friends can be found: + /// + /// https://github.com/rust-lang/rust/tree/master/library. + /// + /// If provided, rust-analyzer automatically adds + /// dependencies on sysroot crates. Conversely, + /// if you omit this path, you can specify sysroot + /// dependencies yourself and, for example, have + /// several different "sysroots" in one graph of + /// crates. + sysroot_src?: string; + /// The set of crates comprising the current + /// project. Must include all transitive + /// dependencies as well as sysroot crate (libstd, + /// libcore and such). + crates: Crate[]; +} + +interface Crate { + /// Optional crate name used for display purposes, + /// without affecting semantics. See the `deps` + /// key for semantically-significant crate names. + display_name?: string; + /// Path to the root module of the crate. + root_module: string; + /// Edition of the crate. + edition: "2015" | "2018" | "2021"; + /// Dependencies + deps: Dep[]; + /// Should this crate be treated as a member of + /// current "workspace". + /// + /// By default, inferred from the `root_module` + /// (members are the crates which reside inside + /// the directory opened in the editor). + /// + /// Set this to `false` for things like standard + /// library and 3rd party crates to enable + /// performance optimizations (rust-analyzer + /// assumes that non-member crates don't change). + is_workspace_member?: boolean; + /// Optionally specify the (super)set of `.rs` + /// files comprising this crate. + /// + /// By default, rust-analyzer assumes that only + /// files under `root_module.parent` can belong + /// to a crate. `include_dirs` are included + /// recursively, unless a subdirectory is in + /// `exclude_dirs`. + /// + /// Different crates can share the same `source`. + /// + /// If two crates share an `.rs` file in common, + /// they *must* have the same `source`. + /// rust-analyzer assumes that files from one + /// source can't refer to files in another source. + source?: { + include_dirs: string[]; + exclude_dirs: string[]; + }; + /// The set of cfgs activated for a given crate, like + /// `["unix", "feature=\"foo\"", "feature=\"bar\""]`. + cfg: string[]; + /// Target triple for this Crate. + /// + /// Used when running `rustc --print cfg` + /// to get target-specific cfgs. + target?: string; + /// Environment variables, used for + /// the `env!` macro + env: { [key: string]: string }; + + /// Whether the crate is a proc-macro crate. + is_proc_macro: boolean; + /// For proc-macro crates, path to compiled + /// proc-macro (.so file). + proc_macro_dylib_path?: string; +} + +interface Dep { + /// Index of a crate in the `crates` array. + crate: number; + /// Name as should appear in the (implicit) + /// `extern crate name` declaration. + name: string; +} diff --git a/src/tools/rust-analyzer/editors/code/src/util.ts b/src/tools/rust-analyzer/editors/code/src/util.ts index d93b9caeb16..922fbcbcf35 100644 --- a/src/tools/rust-analyzer/editors/code/src/util.ts +++ b/src/tools/rust-analyzer/editors/code/src/util.ts @@ -150,9 +150,11 @@ export function memoizeAsync<Ret, TThis, Param extends string>( /** Awaitable wrapper around `child_process.exec` */ export function execute(command: string, options: ExecOptions): Promise<string> { + log.info(`running command: ${command}`); return new Promise((resolve, reject) => { exec(command, options, (err, stdout, stderr) => { if (err) { + log.error(err); reject(err); return; } @@ -167,6 +169,21 @@ export function execute(command: string, options: ExecOptions): Promise<string> }); } +export function executeDiscoverProject(command: string, options: ExecOptions): Promise<string> { + log.info(`running command: ${command}`); + return new Promise((resolve, reject) => { + exec(command, options, (err, stdout, _) => { + if (err) { + log.error(err); + reject(err); + return; + } + + resolve(stdout.trimEnd()); + }); + }); +} + export class LazyOutputChannel implements vscode.OutputChannel { constructor(name: string) { this.name = name; diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs index 2ec09d67e3e..abcf59cfe36 100644 --- a/src/tools/rust-installer/src/combiner.rs +++ b/src/tools/rust-installer/src/combiner.rs @@ -1,7 +1,7 @@ use super::Scripter; use super::Tarballer; use crate::{ - compression::{CompressionFormat, CompressionFormats}, + compression::{CompressionFormat, CompressionFormats, CompressionProfile}, util::*, }; use anyhow::{bail, Context, Result}; @@ -48,6 +48,10 @@ actor! { #[clap(value_name = "DIR")] output_dir: String = "./dist", + /// The profile used to compress the tarball. + #[clap(value_name = "FORMAT", default_value_t)] + compression_profile: CompressionProfile, + /// The formats used to compress the tarball #[clap(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, @@ -153,6 +157,7 @@ impl Combiner { .work_dir(self.work_dir) .input(self.package_name) .output(path_to_str(&output)?.into()) + .compression_profile(self.compression_profile) .compression_formats(self.compression_formats.clone()); tarballer.run()?; diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs index 013e05fda58..510c914163c 100644 --- a/src/tools/rust-installer/src/compression.rs +++ b/src/tools/rust-installer/src/compression.rs @@ -4,6 +4,37 @@ use rayon::prelude::*; use std::{convert::TryFrom, fmt, io::Read, io::Write, path::Path, str::FromStr}; use xz2::{read::XzDecoder, write::XzEncoder}; +#[derive(Default, Debug, Copy, Clone)] +pub enum CompressionProfile { + Fast, + #[default] + Balanced, + Best, +} + +impl FromStr for CompressionProfile { + type Err = Error; + + fn from_str(input: &str) -> Result<Self, Error> { + Ok(match input { + "fast" => Self::Fast, + "balanced" => Self::Balanced, + "best" => Self::Best, + other => anyhow::bail!("invalid compression profile: {other}"), + }) + } +} + +impl fmt::Display for CompressionProfile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CompressionProfile::Fast => f.write_str("fast"), + CompressionProfile::Balanced => f.write_str("balanced"), + CompressionProfile::Best => f.write_str("best"), + } + } +} + #[derive(Debug, Copy, Clone)] pub enum CompressionFormat { Gz, @@ -26,7 +57,11 @@ impl CompressionFormat { } } - pub(crate) fn encode(&self, path: impl AsRef<Path>) -> Result<Box<dyn Encoder>, Error> { + pub(crate) fn encode( + &self, + path: impl AsRef<Path>, + profile: CompressionProfile, + ) -> Result<Box<dyn Encoder>, Error> { let mut os = path.as_ref().as_os_str().to_os_string(); os.push(format!(".{}", self.extension())); let path = Path::new(&os); @@ -37,49 +72,64 @@ impl CompressionFormat { let file = crate::util::create_new_file(path)?; Ok(match self { - CompressionFormat::Gz => Box::new(GzEncoder::new(file, flate2::Compression::best())), + CompressionFormat::Gz => Box::new(GzEncoder::new( + file, + match profile { + CompressionProfile::Fast => flate2::Compression::fast(), + CompressionProfile::Balanced => flate2::Compression::new(6), + CompressionProfile::Best => flate2::Compression::best(), + }, + )), CompressionFormat::Xz => { - let mut filters = xz2::stream::Filters::new(); - // the preset is overridden by the other options so it doesn't matter - let mut lzma_ops = xz2::stream::LzmaOptions::new_preset(9).unwrap(); - // This sets the overall dictionary size, which is also how much memory (baseline) - // is needed for decompression. - lzma_ops.dict_size(64 * 1024 * 1024); - // Use the best match finder for compression ratio. - lzma_ops.match_finder(xz2::stream::MatchFinder::BinaryTree4); - lzma_ops.mode(xz2::stream::Mode::Normal); - // Set nice len to the maximum for best compression ratio - lzma_ops.nice_len(273); - // Set depth to a reasonable value, 0 means auto, 1000 is somwhat high but gives - // good results. - lzma_ops.depth(1000); - // 2 is the default and does well for most files - lzma_ops.position_bits(2); - // 0 is the default and does well for most files - lzma_ops.literal_position_bits(0); - // 3 is the default and does well for most files - lzma_ops.literal_context_bits(3); - - filters.lzma2(&lzma_ops); - - let mut builder = xz2::stream::MtStreamBuilder::new(); - builder.filters(filters); - - // On 32-bit platforms limit ourselves to 3 threads, otherwise we exceed memory - // usage this process can take. In the future we'll likely only do super-fast - // compression in CI and move this heavyweight processing to promote-release (which - // is always 64-bit and can run on big-memory machines) but for now this lets us - // move forward. - if std::mem::size_of::<usize>() == 4 { - builder.threads(3); - } else { - builder.threads(6); - } - - let compressor = XzEncoder::new_stream( - std::io::BufWriter::new(file), - builder.encoder().unwrap(), - ); + let encoder = match profile { + CompressionProfile::Fast => { + xz2::stream::MtStreamBuilder::new().threads(6).preset(1).encoder().unwrap() + } + CompressionProfile::Balanced => { + xz2::stream::MtStreamBuilder::new().threads(6).preset(6).encoder().unwrap() + } + CompressionProfile::Best => { + let mut filters = xz2::stream::Filters::new(); + // the preset is overridden by the other options so it doesn't matter + let mut lzma_ops = xz2::stream::LzmaOptions::new_preset(9).unwrap(); + // This sets the overall dictionary size, which is also how much memory (baseline) + // is needed for decompression. + lzma_ops.dict_size(64 * 1024 * 1024); + // Use the best match finder for compression ratio. + lzma_ops.match_finder(xz2::stream::MatchFinder::BinaryTree4); + lzma_ops.mode(xz2::stream::Mode::Normal); + // Set nice len to the maximum for best compression ratio + lzma_ops.nice_len(273); + // Set depth to a reasonable value, 0 means auto, 1000 is somwhat high but gives + // good results. + lzma_ops.depth(1000); + // 2 is the default and does well for most files + lzma_ops.position_bits(2); + // 0 is the default and does well for most files + lzma_ops.literal_position_bits(0); + // 3 is the default and does well for most files + lzma_ops.literal_context_bits(3); + + filters.lzma2(&lzma_ops); + + let mut builder = xz2::stream::MtStreamBuilder::new(); + builder.filters(filters); + + // On 32-bit platforms limit ourselves to 3 threads, otherwise we exceed memory + // usage this process can take. In the future we'll likely only do super-fast + // compression in CI and move this heavyweight processing to promote-release (which + // is always 64-bit and can run on big-memory machines) but for now this lets us + // move forward. + if std::mem::size_of::<usize>() == 4 { + builder.threads(3); + } else { + builder.threads(6); + } + builder.encoder().unwrap() + } + }; + + let compressor = XzEncoder::new_stream(std::io::BufWriter::new(file), encoder); Box::new(compressor) } }) diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs index 1e4d00b0553..ddd1052599d 100644 --- a/src/tools/rust-installer/src/generator.rs +++ b/src/tools/rust-installer/src/generator.rs @@ -1,6 +1,6 @@ use super::Scripter; use super::Tarballer; -use crate::compression::CompressionFormats; +use crate::compression::{CompressionFormats, CompressionProfile}; use crate::util::*; use anyhow::{bail, format_err, Context, Result}; use std::collections::BTreeSet; @@ -54,6 +54,10 @@ actor! { #[clap(value_name = "DIR")] output_dir: String = "./dist", + /// The profile used to compress the tarball. + #[clap(value_name = "FORMAT", default_value_t)] + compression_profile: CompressionProfile, + /// The formats used to compress the tarball #[clap(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, @@ -113,6 +117,7 @@ impl Generator { .work_dir(self.work_dir) .input(self.package_name) .output(path_to_str(&output)?.into()) + .compression_profile(self.compression_profile) .compression_formats(self.compression_formats.clone()); tarballer.run()?; diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs index 76f5af3fa53..592eba8f698 100644 --- a/src/tools/rust-installer/src/tarballer.rs +++ b/src/tools/rust-installer/src/tarballer.rs @@ -6,7 +6,7 @@ use tar::{Builder, Header}; use walkdir::WalkDir; use crate::{ - compression::{CombinedEncoder, CompressionFormats}, + compression::{CombinedEncoder, CompressionFormats, CompressionProfile}, util::*, }; @@ -25,6 +25,10 @@ actor! { #[clap(value_name = "DIR")] work_dir: String = "./workdir", + /// The profile used to compress the tarball. + #[clap(value_name = "FORMAT", default_value_t)] + compression_profile: CompressionProfile, + /// The formats used to compress the tarball. #[clap(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, @@ -38,7 +42,7 @@ impl Tarballer { let encoder = CombinedEncoder::new( self.compression_formats .iter() - .map(|f| f.encode(&tarball_name)) + .map(|f| f.encode(&tarball_name, self.compression_profile)) .collect::<Result<Vec<_>>>()?, ); diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index b296aa2f4e6..8286bd506bc 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -9,6 +9,6 @@ clap = "4.0.32" env_logger = "0.7.1" [dependencies.mdbook] -version = "0.4.25" +version = "0.4.28" default-features = false features = ["search"] diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 8d46a8ce7f1..6b9a9b66a7d 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -79,11 +79,18 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position) "foundElems", "original", "returned", - "typeFilter", "userQuery", "error", ]; - } else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) { + } else if (fullPath.endsWith("elems") || fullPath.endsWith("returned")) { + fieldsToCheck = [ + "name", + "fullPath", + "pathWithoutLast", + "pathLast", + "generics", + ]; + } else if (fullPath.endsWith("generics")) { fieldsToCheck = [ "name", "fullPath", diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 5648e1254ed..22e45082a9f 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -2,7 +2,7 @@ use rustc_ast::ast; use rustc_ast::HasAttrs; -use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_span::{symbol::sym, Span}; use self::doc_comment::DocCommentFormatter; use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle}; @@ -19,20 +19,6 @@ use crate::utils::{count_newlines, mk_sp}; mod doc_comment; -pub(crate) fn contains_name(attrs: &[ast::Attribute], name: Symbol) -> bool { - attrs.iter().any(|attr| attr.has_name(name)) -} - -pub(crate) fn first_attr_value_str_by_name( - attrs: &[ast::Attribute], - name: Symbol, -) -> Option<Symbol> { - attrs - .iter() - .find(|attr| attr.has_name(name)) - .and_then(|attr| attr.value_str()) -} - /// Returns attributes on the given statement. pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] { stmt.attrs() diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 7ab042506bd..6bc53159b38 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -2,13 +2,12 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; use std::path::{Path, PathBuf}; use rustc_ast::token::TokenKind; -use rustc_ast::{ast, ptr}; +use rustc_ast::{ast, attr, ptr}; use rustc_errors::Diagnostic; use rustc_parse::{new_parser_from_file, parser::Parser as RawParser}; use rustc_span::{sym, Span}; use thin_vec::ThinVec; -use crate::attr::first_attr_value_str_by_name; use crate::parse::session::ParseSess; use crate::Input; @@ -93,7 +92,7 @@ pub(crate) enum ParserError { impl<'a> Parser<'a> { pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> { - let path_sym = first_attr_value_str_by_name(attrs, sym::path)?; + let path_sym = attr::first_attr_value_str_by_name(attrs, sym::path)?; let path_str = path_sym.as_str(); // On windows, the base path might have the form diff --git a/src/tools/rustfmt/src/reorder.rs b/src/tools/rustfmt/src/reorder.rs index 9e4a668aa49..3bddf4c1b6a 100644 --- a/src/tools/rustfmt/src/reorder.rs +++ b/src/tools/rustfmt/src/reorder.rs @@ -8,7 +8,7 @@ use std::cmp::{Ord, Ordering}; -use rustc_ast::ast; +use rustc_ast::{ast, attr}; use rustc_span::{symbol::sym, Span}; use crate::config::{Config, GroupImportsTactic}; @@ -167,7 +167,7 @@ fn rewrite_reorderable_or_regroupable_items( } fn contains_macro_use_attr(item: &ast::Item) -> bool { - crate::attr::contains_name(&item.attrs, sym::macro_use) + attr::contains_name(&item.attrs, sym::macro_use) } /// Divides imports into three groups, corresponding to standard, external diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 2d6abe59343..070ce93f97c 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -103,7 +103,7 @@ mod os_impl { // FIXME: we don't need to look at all binaries, only files that have been modified in this branch // (e.g. using `git ls-files`). - walk_no_read(path, |path| filter_dirs(path) || path.ends_with("src/etc"), &mut |entry| { + walk_no_read(&[path], |path| filter_dirs(path) || path.ends_with("src/etc"), &mut |entry| { let file = entry.path(); let extension = file.extension(); let scripts = ["py", "sh", "ps1"]; diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs index 2241375eaae..84b13306805 100644 --- a/src/tools/tidy/src/debug_artifacts.rs +++ b/src/tools/tidy/src/debug_artifacts.rs @@ -1,21 +1,15 @@ //! Tidy check to prevent creation of unnecessary debug artifacts while running tests. -use crate::walk::{filter_dirs, walk}; +use crate::walk::{filter_dirs, filter_not_rust, walk}; use std::path::Path; const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test"; pub fn check(test_dir: &Path, bad: &mut bool) { - walk(test_dir, filter_dirs, &mut |entry, contents| { - let filename = entry.path(); - let is_rust = filename.extension().map_or(false, |ext| ext == "rs"); - if !is_rust { - return; - } - + walk(test_dir, |path| filter_dirs(path) || filter_not_rust(path), &mut |entry, contents| { for (i, line) in contents.lines().enumerate() { if line.contains("borrowck_graphviz_postflow") { - tidy_error!(bad, "{}:{}: {}", filename.display(), i + 1, GRAPHVIZ_POSTFLOW_MSG); + tidy_error!(bad, "{}:{}: {}", entry.path().display(), i + 1, GRAPHVIZ_POSTFLOW_MSG); } } }); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index d71fa5c8be5..a9eb6c8d03f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -260,6 +260,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "valuable", "version_check", "wasi", + "windows", "winapi", "winapi-i686-pc-windows-gnu", "winapi-util", diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 6d94417a10f..f18feda533c 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -9,8 +9,9 @@ //! * All unstable lang features have tests to ensure they are actually unstable. //! * Language features in a group are sorted by feature name. -use crate::walk::{filter_dirs, walk, walk_many}; +use crate::walk::{filter_dirs, filter_not_rust, walk, walk_many}; use std::collections::hash_map::{Entry, HashMap}; +use std::ffi::OsStr; use std::fmt; use std::fs; use std::num::NonZeroU32; @@ -101,17 +102,15 @@ pub fn check( &tests_path.join("rustdoc-ui"), &tests_path.join("rustdoc"), ], - filter_dirs, + |path| { + filter_dirs(path) + || filter_not_rust(path) + || path.file_name() == Some(OsStr::new("features.rs")) + || path.file_name() == Some(OsStr::new("diagnostic_list.rs")) + }, &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); - if !filename.ends_with(".rs") - || filename == "features.rs" - || filename == "diagnostic_list.rs" - { - return; - } - let filen_underscore = filename.replace('-', "_").replace(".rs", ""); let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features); diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index d98758ace4f..f59406c404b 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -13,7 +13,7 @@ use std::path::PathBuf; use std::process; use std::str::FromStr; use std::sync::atomic::{AtomicBool, Ordering}; -use std::thread::{scope, ScopedJoinHandle}; +use std::thread::{self, scope, ScopedJoinHandle}; fn main() { let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into(); @@ -55,16 +55,28 @@ fn main() { VecDeque::with_capacity(concurrency.get()); macro_rules! check { - ($p:ident $(, $args:expr)* ) => { + ($p:ident) => { + check!(@ $p, name=format!("{}", stringify!($p))); + }; + ($p:ident, $path:expr $(, $args:expr)* ) => { + let shortened = $path.strip_prefix(&root_path).unwrap(); + let name = if shortened == std::path::Path::new("") { + format!("{} (.)", stringify!($p)) + } else { + format!("{} ({})", stringify!($p), shortened.display()) + }; + check!(@ $p, name=name, $path $(,$args)*); + }; + (@ $p:ident, name=$name:expr $(, $args:expr)* ) => { drain_handles(&mut handles); - let handle = s.spawn(|| { + let handle = thread::Builder::new().name($name).spawn_scoped(s, || { let mut flag = false; $p::check($($args, )* &mut flag); if (flag) { bad.store(true, Ordering::Relaxed); } - }); + }).unwrap(); handles.push_back(handle); } } @@ -108,7 +120,6 @@ fn main() { check!(edition, &library_path); check!(alphabetical, &src_path); - check!(alphabetical, &tests_path); check!(alphabetical, &compiler_path); check!(alphabetical, &library_path); diff --git a/src/tools/tidy/src/mir_opt_tests.rs b/src/tools/tidy/src/mir_opt_tests.rs index 2a9dcac2e8d..b316e9e9009 100644 --- a/src/tools/tidy/src/mir_opt_tests.rs +++ b/src/tools/tidy/src/mir_opt_tests.rs @@ -3,19 +3,24 @@ use std::collections::HashSet; use std::path::{Path, PathBuf}; +use crate::walk::walk_no_read; + fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) { let mut rs_files = Vec::<PathBuf>::new(); let mut output_files = HashSet::<PathBuf>::new(); - let files = walkdir::WalkDir::new(&path.join("mir-opt")).into_iter(); - for file in files.filter_map(Result::ok).filter(|e| e.file_type().is_file()) { - let filepath = file.path(); - if filepath.extension() == Some("rs".as_ref()) { - rs_files.push(filepath.to_owned()); - } else { - output_files.insert(filepath.to_owned()); - } - } + walk_no_read( + &[&path.join("mir-opt")], + |path| path.file_name() == Some("README.md".as_ref()), + &mut |file| { + let filepath = file.path(); + if filepath.extension() == Some("rs".as_ref()) { + rs_files.push(filepath.to_owned()); + } else { + output_files.insert(filepath.to_owned()); + } + }, + ); for file in rs_files { for bw in [32, 64] { @@ -26,16 +31,14 @@ fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) { } for extra in output_files { - if extra.file_name() != Some("README.md".as_ref()) { - if !bless { - tidy_error!( - bad, - "the following output file is not associated with any mir-opt test, you can remove it: {}", - extra.display() - ); - } else { - let _ = std::fs::remove_file(extra); - } + if !bless { + tidy_error!( + bad, + "the following output file is not associated with any mir-opt test, you can remove it: {}", + extra.display() + ); + } else { + let _ = std::fs::remove_file(extra); } } } diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 868579b4b1a..6b7b27fd526 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -59,7 +59,6 @@ const EXCEPTION_PATHS: &[&str] = &[ "library/std/src/path.rs", "library/std/src/sys_common", // Should only contain abstractions over platforms "library/std/src/net/test.rs", // Utility helpers for tests - "library/std/src/panic.rs", // fuchsia-specific panic backtrace handling "library/std/src/personality.rs", "library/std/src/personality/", ]; diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 75a4586cb7f..a965c98f484 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -19,7 +19,7 @@ use crate::walk::{filter_dirs, walk}; use regex::{Regex, RegexSet}; -use std::path::Path; +use std::{ffi::OsStr, path::Path}; /// Error code markdown is restricted to 80 columns because they can be /// displayed on the console with --example. @@ -228,21 +228,33 @@ fn is_unexplained_ignore(extension: &str, line: &str) -> bool { pub fn check(path: &Path, bad: &mut bool) { fn skip(path: &Path) -> bool { - filter_dirs(path) || skip_markdown_path(path) + if path.file_name().map_or(false, |name| name.to_string_lossy().starts_with(".#")) { + // vim or emacs temporary file + return true; + } + + if filter_dirs(path) || skip_markdown_path(path) { + return true; + } + + let extensions = ["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "goml"]; + if extensions.iter().all(|e| path.extension() != Some(OsStr::new(e))) { + return true; + } + + // We only check CSS files in rustdoc. + path.extension().map_or(false, |e| e == "css") && !is_in(path, "src", "librustdoc") } + let problematic_consts_strings: Vec<String> = (PROBLEMATIC_CONSTS.iter().map(u32::to_string)) .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v))) .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v))) .collect(); let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap(); + walk(path, skip, &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); - let extensions = - [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css", ".ftl", ".goml"]; - if extensions.iter().all(|e| !filename.ends_with(e)) || filename.starts_with(".#") { - return; - } let is_style_file = filename.ends_with(".css"); let under_rustfmt = filename.ends_with(".rs") && @@ -253,11 +265,6 @@ pub fn check(path: &Path, bad: &mut bool) { a.ends_with("src/doc/book") }); - if is_style_file && !is_in(file, "src", "librustdoc") { - // We only check CSS files in rustdoc. - return; - } - if contents.is_empty() { tidy_error!(bad, "{}: empty file", file.display()); } diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs index f41fa4fcce1..e0fa6aceb85 100644 --- a/src/tools/tidy/src/target_specific_tests.rs +++ b/src/tools/tidy/src/target_specific_tests.rs @@ -4,6 +4,8 @@ use std::collections::BTreeMap; use std::path::Path; +use crate::walk::filter_not_rust; + const COMMENT: &str = "//"; const LLVM_COMPONENTS_HEADER: &str = "needs-llvm-components:"; const COMPILE_FLAGS_HEADER: &str = "compile-flags:"; @@ -35,61 +37,57 @@ struct RevisionInfo<'a> { } pub fn check(path: &Path, bad: &mut bool) { - crate::walk::walk( - path, - |path| path.extension().map(|p| p == "rs") == Some(false), - &mut |entry, content| { - let file = entry.path().display(); - let mut header_map = BTreeMap::new(); - iter_header(content, &mut |cfg, directive| { - if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) { - let info = header_map.entry(cfg).or_insert(RevisionInfo::default()); - let comp_vec = info.llvm_components.get_or_insert(Vec::new()); - for component in value.split(' ') { - let component = component.trim(); - if !component.is_empty() { - comp_vec.push(component); - } - } - } else if directive.starts_with(COMPILE_FLAGS_HEADER) { - let compile_flags = &directive[COMPILE_FLAGS_HEADER.len()..]; - if let Some((_, v)) = compile_flags.split_once("--target") { - if let Some((arch, _)) = - v.trim_start_matches(|c| c == ' ' || c == '=').split_once("-") - { - let info = header_map.entry(cfg).or_insert(RevisionInfo::default()); - info.target_arch.replace(arch); - } else { - eprintln!("{file}: seems to have a malformed --target value"); - *bad = true; - } + crate::walk::walk(path, filter_not_rust, &mut |entry, content| { + let file = entry.path().display(); + let mut header_map = BTreeMap::new(); + iter_header(content, &mut |cfg, directive| { + if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) { + let info = header_map.entry(cfg).or_insert(RevisionInfo::default()); + let comp_vec = info.llvm_components.get_or_insert(Vec::new()); + for component in value.split(' ') { + let component = component.trim(); + if !component.is_empty() { + comp_vec.push(component); } } - }); - for (rev, RevisionInfo { target_arch, llvm_components }) in &header_map { - let rev = rev.unwrap_or("[unspecified]"); - match (target_arch, llvm_components) { - (None, None) => {} - (Some(_), None) => { - eprintln!( - "{}: revision {} should specify `{}` as it has `--target` set", - file, rev, LLVM_COMPONENTS_HEADER - ); + } else if directive.starts_with(COMPILE_FLAGS_HEADER) { + let compile_flags = &directive[COMPILE_FLAGS_HEADER.len()..]; + if let Some((_, v)) = compile_flags.split_once("--target") { + if let Some((arch, _)) = + v.trim_start_matches(|c| c == ' ' || c == '=').split_once("-") + { + let info = header_map.entry(cfg).or_insert(RevisionInfo::default()); + info.target_arch.replace(arch); + } else { + eprintln!("{file}: seems to have a malformed --target value"); *bad = true; } - (None, Some(_)) => { - eprintln!( - "{}: revision {} should not specify `{}` as it doesn't need `--target`", - file, rev, LLVM_COMPONENTS_HEADER - ); - *bad = true; - } - (Some(_), Some(_)) => { - // FIXME: check specified components against the target architectures we - // gathered. - } } } - }, - ); + }); + for (rev, RevisionInfo { target_arch, llvm_components }) in &header_map { + let rev = rev.unwrap_or("[unspecified]"); + match (target_arch, llvm_components) { + (None, None) => {} + (Some(_), None) => { + eprintln!( + "{}: revision {} should specify `{}` as it has `--target` set", + file, rev, LLVM_COMPONENTS_HEADER + ); + *bad = true; + } + (None, Some(_)) => { + eprintln!( + "{}: revision {} should not specify `{}` as it doesn't need `--target`", + file, rev, LLVM_COMPONENTS_HEADER + ); + *bad = true; + } + (Some(_), Some(_)) => { + // FIXME: check specified components against the target architectures we + // gathered. + } + } + } + }); } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 15c36923e88..66f5c932be2 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -3,87 +3,83 @@ //! - there are no stray `.stderr` files use ignore::Walk; -use ignore::WalkBuilder; +use std::collections::HashMap; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. const ROOT_ENTRY_LIMIT: usize = 940; const ISSUES_ENTRY_LIMIT: usize = 1978; -fn check_entries(path: &Path, bad: &mut bool) { - for dir in Walk::new(&path.join("ui")) { +fn check_entries(tests_path: &Path, bad: &mut bool) { + let mut directories: HashMap<PathBuf, usize> = HashMap::new(); + + for dir in Walk::new(&tests_path.join("ui")) { if let Ok(entry) = dir { - if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) { - let dir_path = entry.path(); - // Use special values for these dirs. - let is_root = path.join("ui") == dir_path; - let is_issues_dir = path.join("ui/issues") == dir_path; - let limit = if is_root { - ROOT_ENTRY_LIMIT - } else if is_issues_dir { - ISSUES_ENTRY_LIMIT - } else { - ENTRY_LIMIT - }; + let parent = entry.path().parent().unwrap().to_path_buf(); + *directories.entry(parent).or_default() += 1; + } + } - let count = WalkBuilder::new(&dir_path) - .max_depth(Some(1)) - .build() - .into_iter() - .collect::<Vec<_>>() - .len() - - 1; // remove the dir itself + for (dir_path, count) in directories { + // Use special values for these dirs. + let is_root = tests_path.join("ui") == dir_path; + let is_issues_dir = tests_path.join("ui/issues") == dir_path; + let limit = if is_root { + ROOT_ENTRY_LIMIT + } else if is_issues_dir { + ISSUES_ENTRY_LIMIT + } else { + ENTRY_LIMIT + }; - if count > limit { - tidy_error!( - bad, - "following path contains more than {} entries, \ - you should move the test to some relevant subdirectory (current: {}): {}", - limit, - count, - dir_path.display() - ); - } - } + if count > limit { + tidy_error!( + bad, + "following path contains more than {} entries, \ + you should move the test to some relevant subdirectory (current: {}): {}", + limit, + count, + dir_path.display() + ); } } } pub fn check(path: &Path, bad: &mut bool) { check_entries(&path, bad); - for path in &[&path.join("ui"), &path.join("ui-fulldeps")] { - crate::walk::walk_no_read(path, |_| false, &mut |entry| { - let file_path = entry.path(); - if let Some(ext) = file_path.extension() { - if ext == "stderr" || ext == "stdout" { - // Test output filenames have one of the formats: - // ``` - // $testname.stderr - // $testname.$mode.stderr - // $testname.$revision.stderr - // $testname.$revision.$mode.stderr - // ``` - // - // For now, just make sure that there is a corresponding - // `$testname.rs` file. - // - // NB: We do not use file_stem() as some file names have multiple `.`s and we - // must strip all of them. - let testname = - file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; - if !file_path.with_file_name(testname).with_extension("rs").exists() { - tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path); - } + let (ui, ui_fulldeps) = (path.join("ui"), path.join("ui-fulldeps")); + let paths = [ui.as_path(), ui_fulldeps.as_path()]; + crate::walk::walk_no_read(&paths, |_| false, &mut |entry| { + let file_path = entry.path(); + if let Some(ext) = file_path.extension() { + if ext == "stderr" || ext == "stdout" { + // Test output filenames have one of the formats: + // ``` + // $testname.stderr + // $testname.$mode.stderr + // $testname.$revision.stderr + // $testname.$revision.$mode.stderr + // ``` + // + // For now, just make sure that there is a corresponding + // `$testname.rs` file. + // + // NB: We do not use file_stem() as some file names have multiple `.`s and we + // must strip all of them. + let testname = + file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; + if !file_path.with_file_name(testname).with_extension("rs").exists() { + tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path); + } - if let Ok(metadata) = fs::metadata(file_path) { - if metadata.len() == 0 { - tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); - } + if let Ok(metadata) = fs::metadata(file_path) { + if metadata.len() == 0 { + tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); } } } - }); - } + } + }); } diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index 94152e75168..67a4df19fcc 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -1,6 +1,6 @@ use ignore::DirEntry; -use std::{fs::File, io::Read, path::Path}; +use std::{ffi::OsStr, fs::File, io::Read, path::Path}; /// The default directory filter. pub fn filter_dirs(path: &Path) -> bool { @@ -29,27 +29,31 @@ pub fn filter_dirs(path: &Path) -> bool { // Filter RLS output directories "target/rls", "src/bootstrap/target", + "vendor", ]; skip.iter().any(|p| path.ends_with(p)) } -pub fn walk_many( - paths: &[&Path], +/// Filter for only files that end in `.rs`. +pub fn filter_not_rust(path: &Path) -> bool { + path.extension() != Some(OsStr::new("rs")) && !path.is_dir() +} + +pub fn walk( + path: &Path, skip: impl Clone + Send + Sync + 'static + Fn(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str), ) { - for path in paths { - walk(path, skip.clone(), f); - } + walk_many(&[path], skip, f); } -pub fn walk( - path: &Path, - skip: impl Send + Sync + 'static + Fn(&Path) -> bool, +pub fn walk_many( + paths: &[&Path], + skip: impl Clone + Send + Sync + 'static + Fn(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str), ) { let mut contents = Vec::new(); - walk_no_read(path, skip, &mut |entry| { + walk_no_read(paths, skip, &mut |entry| { contents.clear(); let mut file = t!(File::open(entry.path()), entry.path()); t!(file.read_to_end(&mut contents), entry.path()); @@ -62,11 +66,14 @@ pub fn walk( } pub(crate) fn walk_no_read( - path: &Path, + paths: &[&Path], skip: impl Send + Sync + 'static + Fn(&Path) -> bool, f: &mut dyn FnMut(&DirEntry), ) { - let mut walker = ignore::WalkBuilder::new(path); + let mut walker = ignore::WalkBuilder::new(paths[0]); + for path in &paths[1..] { + walker.add(path); + } let walker = walker.filter_entry(move |e| !skip(e.path())); for entry in walker.build() { if let Ok(entry) = entry { diff --git a/src/tools/unicode-table-generator/src/case_mapping.rs b/src/tools/unicode-table-generator/src/case_mapping.rs index 992aac1f857..7a978db62b4 100644 --- a/src/tools/unicode-table-generator/src/case_mapping.rs +++ b/src/tools/unicode-table-generator/src/case_mapping.rs @@ -1,36 +1,62 @@ use crate::{fmt_list, UnicodeData}; -use std::fmt; +use std::{ + char, + collections::BTreeMap, + fmt::{self, Write}, +}; + +const INDEX_MASK: u32 = 1 << 22; pub(crate) fn generate_case_mapping(data: &UnicodeData) -> String { let mut file = String::new(); + write!(file, "const INDEX_MASK: u32 = 0x{:x};", INDEX_MASK).unwrap(); + file.push_str("\n\n"); file.push_str(HEADER.trim_start()); - - let decl_type = "&[(char, [char; 3])]"; - - file.push_str(&format!( - "static LOWERCASE_TABLE: {} = &[{}];", - decl_type, - fmt_list(data.to_lower.iter().map(to_mapping)) - )); + file.push('\n'); + file.push_str(&generate_tables("LOWER", &data.to_lower)); file.push_str("\n\n"); - file.push_str(&format!( - "static UPPERCASE_TABLE: {} = &[{}];", - decl_type, - fmt_list(data.to_upper.iter().map(to_mapping)) - )); + file.push_str(&generate_tables("UPPER", &data.to_upper)); file } -fn to_mapping((key, (a, b, c)): (&u32, &(u32, u32, u32))) -> (CharEscape, [CharEscape; 3]) { - ( - CharEscape(std::char::from_u32(*key).unwrap()), - [ - CharEscape(std::char::from_u32(*a).unwrap()), - CharEscape(std::char::from_u32(*b).unwrap()), - CharEscape(std::char::from_u32(*c).unwrap()), - ], - ) +fn generate_tables(case: &str, data: &BTreeMap<u32, (u32, u32, u32)>) -> String { + let mut mappings = Vec::with_capacity(data.len()); + let mut multis = Vec::new(); + + for (&key, &(a, b, c)) in data.iter() { + let key = char::from_u32(key).unwrap(); + + if key.is_ascii() { + continue; + } + + let value = if b == 0 && c == 0 { + a + } else { + multis.push([ + CharEscape(char::from_u32(a).unwrap()), + CharEscape(char::from_u32(b).unwrap()), + CharEscape(char::from_u32(c).unwrap()), + ]); + + INDEX_MASK | (u32::try_from(multis.len()).unwrap() - 1) + }; + + mappings.push((CharEscape(key), value)); + } + + let mut tables = String::new(); + + write!(tables, "static {}CASE_TABLE: &[(char, u32)] = &[{}];", case, fmt_list(mappings)) + .unwrap(); + + tables.push_str("\n\n"); + + write!(tables, "static {}CASE_TABLE_MULTI: &[[char; 3]] = &[{}];", case, fmt_list(multis)) + .unwrap(); + + tables } struct CharEscape(char); @@ -46,10 +72,16 @@ pub fn to_lower(c: char) -> [char; 3] { if c.is_ascii() { [(c as u8).to_ascii_lowercase() as char, '\0', '\0'] } else { - match bsearch_case_table(c, LOWERCASE_TABLE) { - None => [c, '\0', '\0'], - Some(index) => LOWERCASE_TABLE[index].1, - } + LOWERCASE_TABLE + .binary_search_by(|&(key, _)| key.cmp(&c)) + .map(|i| { + let u = LOWERCASE_TABLE[i].1; + char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { + // SAFETY: Index comes from statically generated table + unsafe { *LOWERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } + }) + }) + .unwrap_or([c, '\0', '\0']) } } @@ -57,14 +89,16 @@ pub fn to_upper(c: char) -> [char; 3] { if c.is_ascii() { [(c as u8).to_ascii_uppercase() as char, '\0', '\0'] } else { - match bsearch_case_table(c, UPPERCASE_TABLE) { - None => [c, '\0', '\0'], - Some(index) => UPPERCASE_TABLE[index].1, - } + UPPERCASE_TABLE + .binary_search_by(|&(key, _)| key.cmp(&c)) + .map(|i| { + let u = UPPERCASE_TABLE[i].1; + char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { + // SAFETY: Index comes from statically generated table + unsafe { *UPPERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } + }) + }) + .unwrap_or([c, '\0', '\0']) } } - -fn bsearch_case_table(c: char, table: &[(char, [char; 3])]) -> Option<usize> { - table.binary_search_by(|&(key, _)| key.cmp(&c)).ok() -} "; diff --git a/tests/assembly/is_aligned.rs b/tests/assembly/is_aligned.rs index 620a3da9463..148d11ee4d6 100644 --- a/tests/assembly/is_aligned.rs +++ b/tests/assembly/is_aligned.rs @@ -1,6 +1,7 @@ // assembly-output: emit-asm // min-llvm-version: 15.0 // only-x86_64 +// ignore-sgx // revisions: opt-speed opt-size // [opt-speed] compile-flags: -Copt-level=1 // [opt-size] compile-flags: -Copt-level=s diff --git a/tests/assembly/strict_provenance.rs b/tests/assembly/strict_provenance.rs index 01f1957d5f6..24a7c6b5bf1 100644 --- a/tests/assembly/strict_provenance.rs +++ b/tests/assembly/strict_provenance.rs @@ -1,6 +1,7 @@ // assembly-output: emit-asm // compile-flags: -Copt-level=1 // only-x86_64 +// ignore-sgx // min-llvm-version: 15.0 #![crate_type = "rlib"] diff --git a/tests/assembly/x86_64-floating-point-clamp.rs b/tests/assembly/x86_64-floating-point-clamp.rs index 0f3b465d08d..0bc6baad479 100644 --- a/tests/assembly/x86_64-floating-point-clamp.rs +++ b/tests/assembly/x86_64-floating-point-clamp.rs @@ -4,6 +4,7 @@ // assembly-output: emit-asm // compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel // only-x86_64 +// ignore-sgx // CHECK-LABEL: clamp_demo: #[no_mangle] diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs index 79d82cf70d3..7eb3c6948ac 100644 --- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs +++ b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -11,7 +11,7 @@ pub extern fn plus_one(r: &mut u64) { // CHECK: plus_one // CHECK: lfence -// CHECK-NEXT: addq +// CHECK-NEXT: incq // CHECK: popq [[REGISTER:%[a-z]+]] // CHECK-NEXT: lfence // CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs index c316379d5b1..4745ebc4fcd 100644 --- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs +++ b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -10,9 +10,7 @@ use std::arch::asm; pub extern "C" fn get(ptr: *const u64) -> u64 { let value: u64; unsafe { - asm!(".start_inline_asm:", - "mov {}, [{}]", - ".end_inline_asm:", + asm!("mov {}, [{}]", out(reg) value, in(reg) ptr); } @@ -20,24 +18,17 @@ pub extern "C" fn get(ptr: *const u64) -> u64 { } // CHECK: get -// CHECK: .start_inline_asm -// CHECK-NEXT: movq +// CHECK: movq // CHECK-NEXT: lfence -// CHECK-NEXT: .end_inline_asm #[no_mangle] pub extern "C" fn myret() { unsafe { - asm!( - ".start_myret_inline_asm:", - "ret", - ".end_myret_inline_asm:", - ); + asm!("ret"); } } // CHECK: myret -// CHECK: .start_myret_inline_asm -// CHECK-NEXT: shlq $0, (%rsp) +// CHECK: shlq $0, (%rsp) // CHECK-NEXT: lfence // CHECK-NEXT: retq diff --git a/tests/assembly/x86_64-no-jump-tables.rs b/tests/assembly/x86_64-no-jump-tables.rs index 007c3591a4a..edf4adaad41 100644 --- a/tests/assembly/x86_64-no-jump-tables.rs +++ b/tests/assembly/x86_64-no-jump-tables.rs @@ -6,6 +6,7 @@ // compile-flags: -O // [set] compile-flags: -Zno-jump-tables // only-x86_64 +// ignore-sgx #![crate_type = "lib"] diff --git a/tests/codegen/adjustments.rs b/tests/codegen/adjustments.rs index 6d224751752..b53a68a5588 100644 --- a/tests/codegen/adjustments.rs +++ b/tests/codegen/adjustments.rs @@ -13,7 +13,7 @@ pub fn helper(_: usize) { pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] { // We used to generate an extra alloca and memcpy for the block's trailing expression value, so // check that we copy directly to the return value slot -// CHECK: %0 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } undef, {{\[0 x i8\]\*|ptr}} %x.0, 0 +// CHECK: %0 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } poison, {{\[0 x i8\]\*|ptr}} %x.0, 0 // CHECK: %1 = insertvalue { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } %0, [[USIZE]] %x.1, 1 // CHECK: ret { {{\[0 x i8\]\*|ptr}}, [[USIZE]] } %1 { x } diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index ac8cba06b48..7f383a5c149 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -13,8 +13,8 @@ pub fn sum(x: u32, y: u32) -> u32 { // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y) // NO-NEXT: start: -// NO-NEXT: %z = add i32 %y, %x -// NO-NEXT: ret i32 %z +// NO-NEXT: %0 = add i32 %y, %x +// NO-NEXT: ret i32 %0 let z = x + y; z } diff --git a/tests/codegen/inherit_overflow.rs b/tests/codegen/inherit_overflow.rs index 0b0b890b2c9..39909d7abfd 100644 --- a/tests/codegen/inherit_overflow.rs +++ b/tests/codegen/inherit_overflow.rs @@ -4,7 +4,7 @@ //[NOASSERT] compile-flags: -Coverflow-checks=off // CHECK-LABEL: define{{.*}} @assertion -// ASSERT: call void @_ZN4core9panicking5panic17h +// ASSERT: call void @{{.*4core9panicking5panic}} // NOASSERT: ret i8 0 #[no_mangle] pub fn assertion() -> u8 { diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs new file mode 100644 index 00000000000..cefcf9ed9ca --- /dev/null +++ b/tests/codegen/intrinsics/transmute.rs @@ -0,0 +1,196 @@ +// compile-flags: -O -C no-prepopulate-passes +// only-64bit (so I don't need to worry about usize) +// min-llvm-version: 15.0 # this test assumes `ptr`s + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(custom_mir)] +#![feature(inline_const)] + +use std::mem::transmute; + +// Some of the cases here are statically rejected by `mem::transmute`, so +// we need to generate custom MIR for those cases to get to codegen. +use std::intrinsics::mir::*; + +enum Never {} + +#[repr(align(2))] +pub struct BigNever(Never, u16, Never); + +#[repr(align(8))] +pub struct Scalar64(i64); + +#[repr(C, align(4))] +pub struct Aggregate64(u16, u8, i8, f32); + +// CHECK-LABEL: @check_bigger_size( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_bigger_size(x: u16) -> u32 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_smaller_size( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_smaller_size(x: u32) -> u16 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_to_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_to_uninhabited(x: u16) -> BigNever { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_from_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_to_newtype( +#[no_mangle] +pub unsafe fn check_to_newtype(x: u64) -> Scalar64 { + // CHECK: %0 = alloca i64 + // CHECK: store i64 %x, ptr %0 + // CHECK: %1 = load i64, ptr %0 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_newtype( +#[no_mangle] +pub unsafe fn check_from_newtype(x: Scalar64) -> u64 { + // CHECK: %0 = alloca i64 + // CHECK: store i64 %x, ptr %0 + // CHECK: %1 = load i64, ptr %0 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_to_pair( +#[no_mangle] +pub unsafe fn check_to_pair(x: u64) -> Option<i32> { + // CHECK: %0 = alloca { i32, i32 }, align 4 + // CHECK: store i64 %x, ptr %0, align 4 + transmute(x) +} + +// CHECK-LABEL: @check_from_pair( +#[no_mangle] +pub unsafe fn check_from_pair(x: Option<i32>) -> u64 { + // The two arguments are of types that are only 4-aligned, but they're + // immediates so we can write using the destination alloca's alignment. + const { assert!(std::mem::align_of::<Option<i32>>() == 4) }; + + // CHECK: %0 = alloca i64, align 8 + // CHECK: store i32 %x.0, ptr %1, align 8 + // CHECK: store i32 %x.1, ptr %2, align 4 + // CHECK: %3 = load i64, ptr %0, align 8 + // CHECK: ret i64 %3 + transmute(x) +} + +// CHECK-LABEL: @check_to_float( +#[no_mangle] +pub unsafe fn check_to_float(x: u32) -> f32 { + // CHECK: %0 = alloca float + // CHECK: store i32 %x, ptr %0 + // CHECK: %1 = load float, ptr %0 + // CHECK: ret float %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_float( +#[no_mangle] +pub unsafe fn check_from_float(x: f32) -> u32 { + // CHECK: %0 = alloca i32 + // CHECK: store float %x, ptr %0 + // CHECK: %1 = load i32, ptr %0 + // CHECK: ret i32 %1 + transmute(x) +} + +// CHECK-LABEL: @check_to_bytes( +#[no_mangle] +pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] { + // CHECK: %0 = alloca [4 x i8], align 1 + // CHECK: store i32 %x, ptr %0, align 1 + // CHECK: %1 = load i32, ptr %0, align 1 + // CHECK: ret i32 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_bytes( +#[no_mangle] +pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 { + // CHECK: %1 = alloca i32, align 4 + // CHECK: %x = alloca [4 x i8], align 1 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %1, ptr align 1 %x, i64 4, i1 false) + // CHECK: %3 = load i32, ptr %1, align 4 + // CHECK: ret i32 %3 + transmute(x) +} + +// CHECK-LABEL: @check_to_aggregate( +#[no_mangle] +pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 { + // CHECK: %0 = alloca %Aggregate64, align 4 + // CHECK: store i64 %x, ptr %0, align 4 + // CHECK: %1 = load i64, ptr %0, align 4 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_aggregate( +#[no_mangle] +pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 { + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %{{[0-9]+}}, ptr align 4 %x, i64 8, i1 false) + transmute(x) +} + +// CHECK-LABEL: @check_long_array_less_aligned( +#[no_mangle] +pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] { + // CHECK-NEXT: start + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %0, ptr align 8 %x, i64 800, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} + +// CHECK-LABEL: @check_long_array_more_aligned( +#[no_mangle] +pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] { + // CHECK-NEXT: start + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 1 %x, i64 100, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} diff --git a/tests/codegen/auxiliary/static_dllimport_aux.rs b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs index afb0dc42f44..afb0dc42f44 100644 --- a/tests/codegen/auxiliary/static_dllimport_aux.rs +++ b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs diff --git a/tests/codegen/issue-103285-ptr-addr-overflow-check.rs b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs index a3499babea2..a3499babea2 100644 --- a/tests/codegen/issue-103285-ptr-addr-overflow-check.rs +++ b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs diff --git a/tests/codegen/issue-103840.rs b/tests/codegen/issues/issue-103840.rs index f19d7031bb3..f19d7031bb3 100644 --- a/tests/codegen/issue-103840.rs +++ b/tests/codegen/issues/issue-103840.rs diff --git a/tests/codegen/issue-105386-ub-in-debuginfo.rs b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs index d54ac9e33bc..d54ac9e33bc 100644 --- a/tests/codegen/issue-105386-ub-in-debuginfo.rs +++ b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs diff --git a/tests/codegen/issue-13018.rs b/tests/codegen/issues/issue-13018.rs index b70ea1f48c8..b70ea1f48c8 100644 --- a/tests/codegen/issue-13018.rs +++ b/tests/codegen/issues/issue-13018.rs diff --git a/tests/codegen/issue-15953.rs b/tests/codegen/issues/issue-15953.rs index 28d28428904..28d28428904 100644 --- a/tests/codegen/issue-15953.rs +++ b/tests/codegen/issues/issue-15953.rs diff --git a/tests/codegen/issue-27130.rs b/tests/codegen/issues/issue-27130.rs index e5ee94e1f45..e5ee94e1f45 100644 --- a/tests/codegen/issue-27130.rs +++ b/tests/codegen/issues/issue-27130.rs diff --git a/tests/codegen/issue-32031.rs b/tests/codegen/issues/issue-32031.rs index abef92c19b6..abef92c19b6 100644 --- a/tests/codegen/issue-32031.rs +++ b/tests/codegen/issues/issue-32031.rs diff --git a/tests/codegen/issue-32364.rs b/tests/codegen/issues/issue-32364.rs index 85493a4bb73..85493a4bb73 100644 --- a/tests/codegen/issue-32364.rs +++ b/tests/codegen/issues/issue-32364.rs diff --git a/tests/codegen/issue-34634.rs b/tests/codegen/issues/issue-34634.rs index f53fa240cd1..f53fa240cd1 100644 --- a/tests/codegen/issue-34634.rs +++ b/tests/codegen/issues/issue-34634.rs diff --git a/tests/codegen/issue-34947-pow-i32.rs b/tests/codegen/issues/issue-34947-pow-i32.rs index 653da8e8b5f..653da8e8b5f 100644 --- a/tests/codegen/issue-34947-pow-i32.rs +++ b/tests/codegen/issues/issue-34947-pow-i32.rs diff --git a/tests/codegen/issue-37945.rs b/tests/codegen/issues/issue-37945.rs index fe54375bbf6..fe54375bbf6 100644 --- a/tests/codegen/issue-37945.rs +++ b/tests/codegen/issues/issue-37945.rs diff --git a/tests/codegen/issue-44056-macos-tls-align.rs b/tests/codegen/issues/issue-44056-macos-tls-align.rs index 1a3923f1bb1..1a3923f1bb1 100644 --- a/tests/codegen/issue-44056-macos-tls-align.rs +++ b/tests/codegen/issues/issue-44056-macos-tls-align.rs diff --git a/tests/codegen/issue-45222.rs b/tests/codegen/issues/issue-45222.rs index e9b05e648b4..e9b05e648b4 100644 --- a/tests/codegen/issue-45222.rs +++ b/tests/codegen/issues/issue-45222.rs diff --git a/tests/codegen/issue-45466.rs b/tests/codegen/issues/issue-45466.rs index c7954276777..c7954276777 100644 --- a/tests/codegen/issue-45466.rs +++ b/tests/codegen/issues/issue-45466.rs diff --git a/tests/codegen/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs index 1daa213fc82..1daa213fc82 100644 --- a/tests/codegen/issue-45964-bounds-check-slice-pos.rs +++ b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs diff --git a/tests/codegen/issue-47278.rs b/tests/codegen/issues/issue-47278.rs index 9076274f45e..9076274f45e 100644 --- a/tests/codegen/issue-47278.rs +++ b/tests/codegen/issues/issue-47278.rs diff --git a/tests/codegen/issue-47442.rs b/tests/codegen/issues/issue-47442.rs index 6944336d335..6944336d335 100644 --- a/tests/codegen/issue-47442.rs +++ b/tests/codegen/issues/issue-47442.rs diff --git a/tests/codegen/issue-56267-2.rs b/tests/codegen/issues/issue-56267-2.rs index 4dc9ebfebbc..4dc9ebfebbc 100644 --- a/tests/codegen/issue-56267-2.rs +++ b/tests/codegen/issues/issue-56267-2.rs diff --git a/tests/codegen/issue-56267.rs b/tests/codegen/issues/issue-56267.rs index 7bdd2577998..7bdd2577998 100644 --- a/tests/codegen/issue-56267.rs +++ b/tests/codegen/issues/issue-56267.rs diff --git a/tests/codegen/issue-56927.rs b/tests/codegen/issues/issue-56927.rs index 044d721814b..044d721814b 100644 --- a/tests/codegen/issue-56927.rs +++ b/tests/codegen/issues/issue-56927.rs diff --git a/tests/codegen/issue-58881.rs b/tests/codegen/issues/issue-58881.rs index 00f8953d949..00f8953d949 100644 --- a/tests/codegen/issue-58881.rs +++ b/tests/codegen/issues/issue-58881.rs diff --git a/tests/codegen/issue-59352.rs b/tests/codegen/issues/issue-59352.rs index d271fe027e3..d271fe027e3 100644 --- a/tests/codegen/issue-59352.rs +++ b/tests/codegen/issues/issue-59352.rs diff --git a/tests/codegen/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs index a3aca3a2912..a3aca3a2912 100644 --- a/tests/codegen/issue-69101-bounds-check.rs +++ b/tests/codegen/issues/issue-69101-bounds-check.rs diff --git a/tests/codegen/issue-73031.rs b/tests/codegen/issues/issue-73031.rs index a09c4bcfbea..a09c4bcfbea 100644 --- a/tests/codegen/issue-73031.rs +++ b/tests/codegen/issues/issue-73031.rs diff --git a/tests/codegen/issue-73338-effecient-cmp.rs b/tests/codegen/issues/issue-73338-effecient-cmp.rs index 85c2bbfd040..85c2bbfd040 100644 --- a/tests/codegen/issue-73338-effecient-cmp.rs +++ b/tests/codegen/issues/issue-73338-effecient-cmp.rs diff --git a/tests/codegen/issue-73396-bounds-check-after-position.rs b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs index 8d07a67a1b4..8d07a67a1b4 100644 --- a/tests/codegen/issue-73396-bounds-check-after-position.rs +++ b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs diff --git a/tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs index 1ad05906e21..1ad05906e21 100644 --- a/tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs +++ b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs diff --git a/tests/codegen/issue-75525-bounds-checks.rs b/tests/codegen/issues/issue-75525-bounds-checks.rs index 2d363d8f73b..2d363d8f73b 100644 --- a/tests/codegen/issue-75525-bounds-checks.rs +++ b/tests/codegen/issues/issue-75525-bounds-checks.rs diff --git a/tests/codegen/issue-75546.rs b/tests/codegen/issues/issue-75546.rs index 470a9e04096..470a9e04096 100644 --- a/tests/codegen/issue-75546.rs +++ b/tests/codegen/issues/issue-75546.rs diff --git a/tests/codegen/issue-75659.rs b/tests/codegen/issues/issue-75659.rs index 9394868c08d..9394868c08d 100644 --- a/tests/codegen/issue-75659.rs +++ b/tests/codegen/issues/issue-75659.rs diff --git a/tests/codegen/issue-77812.rs b/tests/codegen/issues/issue-77812.rs index 4cc82414546..4cc82414546 100644 --- a/tests/codegen/issue-77812.rs +++ b/tests/codegen/issues/issue-77812.rs diff --git a/tests/codegen/issue-81408-dllimport-thinlto-windows.rs b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs index 0b6ab4f7ecb..0b6ab4f7ecb 100644 --- a/tests/codegen/issue-81408-dllimport-thinlto-windows.rs +++ b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs diff --git a/tests/codegen/issue-84268.rs b/tests/codegen/issues/issue-84268.rs index 7ca19544700..7ca19544700 100644 --- a/tests/codegen/issue-84268.rs +++ b/tests/codegen/issues/issue-84268.rs diff --git a/tests/codegen/issue-85872-multiple-reverse.rs b/tests/codegen/issues/issue-85872-multiple-reverse.rs index 591a1aca747..591a1aca747 100644 --- a/tests/codegen/issue-85872-multiple-reverse.rs +++ b/tests/codegen/issues/issue-85872-multiple-reverse.rs diff --git a/tests/codegen/issue-86106.rs b/tests/codegen/issues/issue-86106.rs index 9ccbcb24f56..9ccbcb24f56 100644 --- a/tests/codegen/issue-86106.rs +++ b/tests/codegen/issues/issue-86106.rs diff --git a/tests/codegen/issue-96274.rs b/tests/codegen/issues/issue-96274.rs index 28bfcce0d7b..28bfcce0d7b 100644 --- a/tests/codegen/issue-96274.rs +++ b/tests/codegen/issues/issue-96274.rs diff --git a/tests/codegen/issue-96497-slice-size-nowrap.rs b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs index 0413ed6b26f..0413ed6b26f 100644 --- a/tests/codegen/issue-96497-slice-size-nowrap.rs +++ b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs diff --git a/tests/codegen/issue-98156-const-arg-temp-lifetime.rs b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs index 12ace5fff6b..12ace5fff6b 100644 --- a/tests/codegen/issue-98156-const-arg-temp-lifetime.rs +++ b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs diff --git a/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs index 7da29cd7952..7da29cd7952 100644 --- a/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs +++ b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index 260dcbac0fc..4d7a80bfbe5 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -1,13 +1,19 @@ // compile-flags: -O -C no-prepopulate-passes +// min-llvm-version: 15.0 # this test assumes `ptr`s and thus no `pointercast`s #![crate_type = "lib"] -// FIXME(eddyb) all of these tests show memory stores and loads, even after a -// scalar `bitcast`, more special-casing is required to remove `alloca` usage. +// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, +// without needing to pointercast, and SRoA will turn that into a `bitcast`. +// As such, there's no longer special-casing in `transmute` to attempt to +// generate `bitcast` ourselves, as that just made the IR longer. + +// FIXME: That said, `bitcast`s could still be a valuable addition if they could +// be done in `rvalue_creates_operand`, and thus avoid the `alloca`s entirely. // CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x) -// CHECK: store i32 %{{.*}}, {{.*}} %0 -// CHECK-NEXT: %[[RES:.*]] = load i32, {{.*}} %0 +// CHECK: store float %{{.*}}, ptr %0 +// CHECK-NEXT: %[[RES:.*]] = load i32, ptr %0 // CHECK: ret i32 %[[RES]] #[no_mangle] pub fn f32_to_bits(x: f32) -> u32 { @@ -25,12 +31,10 @@ pub fn bool_to_byte(b: bool) -> u8 { } // CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte) -// CHECK: %1 = trunc i8 %byte to i1 -// CHECK-NEXT: %2 = zext i1 %1 to i8 -// CHECK-NEXT: store i8 %2, {{.*}} %0 -// CHECK-NEXT: %3 = load i8, {{.*}} %0 -// CHECK-NEXT: %4 = trunc i8 %3 to i1 -// CHECK: ret i1 %4 +// CHECK: store i8 %byte, ptr %0 +// CHECK-NEXT: %1 = load i8, {{.*}} %0 +// CHECK-NEXT: %2 = trunc i8 %1 to i1 +// CHECK: ret i1 %2 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { std::mem::transmute(byte) @@ -45,20 +49,8 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { unsafe { std::mem::transmute(p) } } -// HACK(eddyb) scalar `transmute`s between pointers and non-pointers are -// currently not special-cased like other scalar `transmute`s, because -// LLVM requires specifically `ptrtoint`/`inttoptr` instead of `bitcast`. -// -// Tests below show the non-special-cased behavior (with the possible -// future special-cased instructions in the "NOTE(eddyb)" comments). - // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p) - -// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: -// %2 = ptrtoint i16* %p to [[USIZE]] -// store [[USIZE]] %2, [[USIZE]]* %0 // CHECK: store {{i16\*|ptr}} %p, {{.*}} - // CHECK-NEXT: %[[RES:.*]] = load [[USIZE]], {{.*}} %0 // CHECK: ret [[USIZE]] %[[RES]] #[no_mangle] @@ -67,12 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize { } // CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i) - -// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: -// %2 = inttoptr [[USIZE]] %i to i16* -// store i16* %2, i16** %0 // CHECK: store [[USIZE]] %i, {{.*}} - // CHECK-NEXT: %[[RES:.*]] = load {{i16\*|ptr}}, {{.*}} %0 // CHECK: ret {{i16\*|ptr}} %[[RES]] #[no_mangle] diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs index d4715efad73..53841df32e8 100644 --- a/tests/codegen/var-names.rs +++ b/tests/codegen/var-names.rs @@ -9,7 +9,7 @@ pub fn test(a: u32, b: u32) -> u32 { // CHECK: %c = add i32 %a, %b let d = c; let e = d * a; - // CHECK-NEXT: %e = mul i32 %c, %a + // CHECK-NEXT: %0 = mul i32 %c, %a e - // CHECK-NEXT: ret i32 %e + // CHECK-NEXT: ret i32 %0 } diff --git a/tests/codegen/vec-as-ptr.rs b/tests/codegen/vec-as-ptr.rs new file mode 100644 index 00000000000..8ff7ba9cb64 --- /dev/null +++ b/tests/codegen/vec-as-ptr.rs @@ -0,0 +1,19 @@ +// compile-flags: -O -Zmerge-functions=disabled + +#![crate_type = "lib"] + +// Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this +// pointer is nonnull. +// CHECK: nonnull {{i8\*|ptr}} @vec_as_ptr +#[no_mangle] +pub fn vec_as_ptr(v: &Vec<u8>) -> *const u8 { + v.as_ptr() +} + +// Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this +// pointer is nonnull. +// CHECK: nonnull {{i8\*|ptr}} @vec_as_mut_ptr +#[no_mangle] +pub fn vec_as_mut_ptr(v: &mut Vec<u8>) -> *mut u8 { + v.as_mut_ptr() +} diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs index aa6589dc35b..b3c3483fea9 100644 --- a/tests/codegen/vec-shrink-panik.rs +++ b/tests/codegen/vec-shrink-panik.rs @@ -1,3 +1,8 @@ +// revisions: old new +// LLVM 17 realizes double panic is not possible and doesn't generate calls +// to panic_cannot_unwind. +// [old]ignore-llvm-version: 17 - 99 +// [new]min-llvm-version: 17 // compile-flags: -O // ignore-debug: the debug assertions get in the way #![crate_type = "lib"] @@ -18,11 +23,11 @@ pub fn shrink_to_fit(vec: &mut Vec<u32>) { pub fn issue71861(vec: Vec<u32>) -> Box<[u32]> { // CHECK-NOT: panic - // Call to panic_cannot_unwind in case of double-panic is expected, - // but other panics are not. + // Call to panic_cannot_unwind in case of double-panic is expected + // on LLVM 16 and older, but other panics are not. // CHECK: cleanup - // CHECK-NEXT: ; call core::panicking::panic_cannot_unwind - // CHECK-NEXT: panic_cannot_unwind + // old-NEXT: ; call core::panicking::panic_cannot_unwind + // old-NEXT: panic_cannot_unwind // CHECK-NOT: panic vec.into_boxed_slice() @@ -34,14 +39,14 @@ pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> { // CHECK-NOT: panic // Call to panic_cannot_unwind in case of double-panic is expected, - // but other panics are not. + // on LLVM 16 and older, but other panics are not. // CHECK: cleanup - // CHECK-NEXT: ; call core::panicking::panic_cannot_unwind - // CHECK-NEXT: panic_cannot_unwind + // old-NEXT: ; call core::panicking::panic_cannot_unwind + // old-NEXT: panic_cannot_unwind // CHECK-NOT: panic iter.iter().copied().collect() } -// CHECK: ; core::panicking::panic_cannot_unwind -// CHECK: declare void @{{.*}}panic_cannot_unwind +// old: ; core::panicking::panic_cannot_unwind +// old: declare void @{{.*}}panic_cannot_unwind diff --git a/tests/debuginfo/type-names.rs b/tests/debuginfo/type-names.rs index d7b79a845d2..c5ce044dd53 100644 --- a/tests/debuginfo/type-names.rs +++ b/tests/debuginfo/type-names.rs @@ -175,7 +175,6 @@ // 0-sized structs appear to be optimized away in some cases, so only check the structs that do // actually appear. // cdb-command:dv /t *_struct -// cdb-check:struct type_names::GenericStruct<enum2$<type_names::mod1::Enum2>,f64> mut_generic_struct = [...] // ENUMS // cdb-command:dv /t *_enum_* diff --git a/tests/incremental/auxiliary/circular-dependencies-aux.rs b/tests/incremental/auxiliary/circular-dependencies-aux.rs new file mode 100644 index 00000000000..0e74eb1b2f2 --- /dev/null +++ b/tests/incremental/auxiliary/circular-dependencies-aux.rs @@ -0,0 +1,10 @@ +// edition: 2021 +// compile-flags: --crate-type lib --extern circular_dependencies={{build-base}}/circular-dependencies/libcircular_dependencies.rmeta --emit dep-info,metadata + +use circular_dependencies::Foo; + +pub fn consume_foo(_: Foo) {} + +pub fn produce_foo() -> Foo { + Foo +} diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs new file mode 100644 index 00000000000..10673066a9d --- /dev/null +++ b/tests/incremental/circular-dependencies.rs @@ -0,0 +1,37 @@ +// ignore-tidy-linelength +// revisions: cpass1 cfail2 +// edition: 2021 +// [cpass1] compile-flags: --crate-type lib --emit dep-info,metadata +// [cfail2] aux-build: circular-dependencies-aux.rs +// [cfail2] compile-flags: --test --extern aux={{build-base}}/circular-dependencies/auxiliary/libcircular_dependencies_aux.rmeta -L dependency={{build-base}}/circular-dependencies + +pub struct Foo; +//[cfail2]~^ NOTE `Foo` is defined in the current crate +//[cfail2]~| NOTE `Foo` is defined in the current crate +//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies` +//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies` + +pub fn consume_foo(_: Foo) {} +//[cfail2]~^ NOTE function defined here + +pub fn produce_foo() -> Foo { + Foo +} + +#[test] +fn test() { + aux::consume_foo(produce_foo()); + //[cfail2]~^ ERROR mismatched types [E0308] + //[cfail2]~| NOTE expected `circular_dependencies::Foo`, found `Foo` + //[cfail2]~| NOTE arguments to this function are incorrect + //[cfail2]~| NOTE `Foo` and `circular_dependencies::Foo` have similar names, but are actually distinct types + //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations + //[cfail2]~| NOTE function defined here + + consume_foo(aux::produce_foo()); + //[cfail2]~^ ERROR mismatched types [E0308] + //[cfail2]~| NOTE expected `Foo`, found `circular_dependencies::Foo` + //[cfail2]~| NOTE arguments to this function are incorrect + //[cfail2]~| NOTE `circular_dependencies::Foo` and `Foo` have similar names, but are actually distinct types + //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations +} diff --git a/tests/incremental/hashes/let_expressions.rs b/tests/incremental/hashes/let_expressions.rs index 180bf6fec87..7aca4324233 100644 --- a/tests/incremental/hashes/let_expressions.rs +++ b/tests/incremental/hashes/let_expressions.rs @@ -193,9 +193,9 @@ pub fn add_initializer() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail6")] pub fn add_initializer() { let _x: i16 = 3i16; diff --git a/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir new file mode 100644 index 00000000000..49e8c812c19 --- /dev/null +++ b/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir @@ -0,0 +1,16 @@ +// MIR for `adt` after built + +fn adt() -> Onion { + let mut _0: Onion; // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:13: +0:18 + let mut _1: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _2: Foo; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: Bar; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _1 = const 1_i32; // scope 0 at $DIR/aggregate_exprs.rs:+6:13: +6:20 + _2 = Foo { a: const 1_i32, b: const 2_i32 }; // scope 0 at $DIR/aggregate_exprs.rs:+7:13: +10:14 + _3 = Bar::Foo(move _2, _1); // scope 0 at $DIR/aggregate_exprs.rs:+11:13: +11:39 + _0 = Onion { neon: ((_3 as variant#0).1: i32) }; // scope 0 at $DIR/aggregate_exprs.rs:+12:13: +12:58 + return; // scope 0 at $DIR/aggregate_exprs.rs:+13:13: +13:21 + } +} diff --git a/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir new file mode 100644 index 00000000000..30d12897331 --- /dev/null +++ b/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir @@ -0,0 +1,15 @@ +// MIR for `array` after built + +fn array() -> [i32; 2] { + let mut _0: [i32; 2]; // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:15: +0:23 + let mut _1: [i32; 2]; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _2: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _1 = [const 42_i32, const 43_i32]; // scope 0 at $DIR/aggregate_exprs.rs:+5:13: +5:25 + _2 = const 1_i32; // scope 0 at $DIR/aggregate_exprs.rs:+6:13: +6:20 + _1 = [_2, const 2_i32]; // scope 0 at $DIR/aggregate_exprs.rs:+7:13: +7:25 + _0 = move _1; // scope 0 at $DIR/aggregate_exprs.rs:+8:13: +8:26 + return; // scope 0 at $DIR/aggregate_exprs.rs:+9:13: +9:21 + } +} diff --git a/tests/mir-opt/building/custom/aggregate_exprs.rs b/tests/mir-opt/building/custom/aggregate_exprs.rs new file mode 100644 index 00000000000..554c9c03ba4 --- /dev/null +++ b/tests/mir-opt/building/custom/aggregate_exprs.rs @@ -0,0 +1,71 @@ +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +// EMIT_MIR aggregate_exprs.tuple.built.after.mir +#[custom_mir(dialect = "built")] +fn tuple() -> (i32, bool) { + mir!( + { + RET = (1, true); + Return() + } + ) +} + +// EMIT_MIR aggregate_exprs.array.built.after.mir +#[custom_mir(dialect = "built")] +fn array() -> [i32; 2] { + mir!( + let x: [i32; 2]; + let one: i32; + { + x = [42, 43]; + one = 1; + x = [one, 2]; + RET = Move(x); + Return() + } + ) +} + +struct Foo { + a: i32, + b: i32, +} + +enum Bar { + Foo(Foo, i32), +} + +union Onion { + neon: i32, + noun: f32, +} + +// EMIT_MIR aggregate_exprs.adt.built.after.mir +#[custom_mir(dialect = "built")] +fn adt() -> Onion { + mir!( + let one: i32; + let x: Foo; + let y: Bar; + { + one = 1; + x = Foo { + a: 1, + b: 2, + }; + y = Bar::Foo(Move(x), one); + RET = Onion { neon: Field(Variant(y, 0), 1) }; + Return() + } + ) +} + +fn main() { + assert_eq!(tuple(), (1, true)); + assert_eq!(array(), [1, 2]); + assert_eq!(unsafe { adt().neon }, 1); +} diff --git a/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir new file mode 100644 index 00000000000..5fe45ccc90c --- /dev/null +++ b/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `tuple` after built + +fn tuple() -> (i32, bool) { + let mut _0: (i32, bool); // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:15: +0:26 + + bb0: { + _0 = (const 1_i32, const true); // scope 0 at $DIR/aggregate_exprs.rs:+3:13: +3:28 + return; // scope 0 at $DIR/aggregate_exprs.rs:+4:13: +4:21 + } +} diff --git a/tests/mir-opt/building/custom/composite_return.rs b/tests/mir-opt/building/custom/composite_return.rs new file mode 100644 index 00000000000..701d6b1ab71 --- /dev/null +++ b/tests/mir-opt/building/custom/composite_return.rs @@ -0,0 +1,21 @@ +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +// EMIT_MIR composite_return.tuple.built.after.mir +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn tuple() -> (i32, bool) { + mir!( + type RET = (i32, bool); + { + RET.0 = 1; + RET.1 = true; + Return() + } + ) +} + +fn main() { + assert_eq!(tuple(), (1, true)); +} diff --git a/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir b/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir new file mode 100644 index 00000000000..d159c1a655e --- /dev/null +++ b/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir @@ -0,0 +1,11 @@ +// MIR for `tuple` after built + +fn tuple() -> (i32, bool) { + let mut _0: (i32, bool); // return place in scope 0 at $DIR/composite_return.rs:+0:15: +0:26 + + bb0: { + (_0.0: i32) = const 1_i32; // scope 0 at $DIR/composite_return.rs:+4:13: +4:22 + (_0.1: bool) = const true; // scope 0 at $DIR/composite_return.rs:+5:13: +5:25 + return; // scope 0 at $DIR/composite_return.rs:+6:13: +6:21 + } +} diff --git a/tests/mir-opt/building/shifts.rs b/tests/mir-opt/building/shifts.rs new file mode 100644 index 00000000000..4b63a00a304 --- /dev/null +++ b/tests/mir-opt/building/shifts.rs @@ -0,0 +1,20 @@ +// compile-flags: -C debug-assertions=yes + +// EMIT_MIR shifts.shift_signed.built.after.mir +fn shift_signed(small: i8, big: u128, a: i8, b: i32, c: i128) -> ([i8; 3], [u128; 3]) { + ( + [small >> a, small >> b, small >> c], + [big << a, big << b, big << c], + ) +} + +// EMIT_MIR shifts.shift_unsigned.built.after.mir +fn shift_unsigned(small: u8, big: i128, a: u8, b: u32, c: u128) -> ([u8; 3], [i128; 3]) { + ( + [small >> a, small >> b, small >> c], + [big << a, big << b, big << c], + ) +} + +fn main() { +} diff --git a/tests/mir-opt/building/shifts.shift_signed.built.after.mir b/tests/mir-opt/building/shifts.shift_signed.built.after.mir new file mode 100644 index 00000000000..028777cefdd --- /dev/null +++ b/tests/mir-opt/building/shifts.shift_signed.built.after.mir @@ -0,0 +1,147 @@ +// MIR for `shift_signed` after built + +fn shift_signed(_1: i8, _2: u128, _3: i8, _4: i32, _5: i128) -> ([i8; 3], [u128; 3]) { + debug small => _1; // in scope 0 at $DIR/shifts.rs:+0:17: +0:22 + debug big => _2; // in scope 0 at $DIR/shifts.rs:+0:28: +0:31 + debug a => _3; // in scope 0 at $DIR/shifts.rs:+0:39: +0:40 + debug b => _4; // in scope 0 at $DIR/shifts.rs:+0:46: +0:47 + debug c => _5; // in scope 0 at $DIR/shifts.rs:+0:54: +0:55 + let mut _0: ([i8; 3], [u128; 3]); // return place in scope 0 at $DIR/shifts.rs:+0:66: +0:86 + let mut _6: [i8; 3]; // in scope 0 at $DIR/shifts.rs:+2:9: +2:45 + let mut _7: i8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _8: i8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:15 + let mut _9: i8; // in scope 0 at $DIR/shifts.rs:+2:19: +2:20 + let mut _10: u8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _11: bool; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _12: i8; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _13: i8; // in scope 0 at $DIR/shifts.rs:+2:22: +2:27 + let mut _14: i32; // in scope 0 at $DIR/shifts.rs:+2:31: +2:32 + let mut _15: u32; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _16: bool; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _17: i8; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _18: i8; // in scope 0 at $DIR/shifts.rs:+2:34: +2:39 + let mut _19: i128; // in scope 0 at $DIR/shifts.rs:+2:43: +2:44 + let mut _20: u128; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _21: bool; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _22: [u128; 3]; // in scope 0 at $DIR/shifts.rs:+3:9: +3:39 + let mut _23: u128; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _24: u128; // in scope 0 at $DIR/shifts.rs:+3:10: +3:13 + let mut _25: i8; // in scope 0 at $DIR/shifts.rs:+3:17: +3:18 + let mut _26: u8; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _27: bool; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _28: u128; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _29: u128; // in scope 0 at $DIR/shifts.rs:+3:20: +3:23 + let mut _30: i32; // in scope 0 at $DIR/shifts.rs:+3:27: +3:28 + let mut _31: u32; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _32: bool; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _33: u128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + let mut _34: u128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:33 + let mut _35: i128; // in scope 0 at $DIR/shifts.rs:+3:37: +3:38 + let mut _36: u128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + let mut _37: bool; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + + bb0: { + StorageLive(_6); // scope 0 at $DIR/shifts.rs:+2:9: +2:45 + StorageLive(_7); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + StorageLive(_8); // scope 0 at $DIR/shifts.rs:+2:10: +2:15 + _8 = _1; // scope 0 at $DIR/shifts.rs:+2:10: +2:15 + StorageLive(_9); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + _9 = _3; // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + _10 = _9 as u8 (IntToInt); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + _11 = Lt(move _10, const 8_u8); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + assert(move _11, "attempt to shift right by `{}`, which would overflow", _9) -> [success: bb1, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + } + + bb1: { + _7 = Shr(move _8, move _9); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + StorageDead(_9); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + StorageDead(_8); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + StorageLive(_12); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + StorageLive(_13); // scope 0 at $DIR/shifts.rs:+2:22: +2:27 + _13 = _1; // scope 0 at $DIR/shifts.rs:+2:22: +2:27 + StorageLive(_14); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + _14 = _4; // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + _15 = _14 as u32 (IntToInt); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + _16 = Lt(move _15, const 8_u32); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + assert(move _16, "attempt to shift right by `{}`, which would overflow", _14) -> [success: bb2, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + } + + bb2: { + _12 = Shr(move _13, move _14); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + StorageDead(_14); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + StorageDead(_13); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + StorageLive(_17); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + StorageLive(_18); // scope 0 at $DIR/shifts.rs:+2:34: +2:39 + _18 = _1; // scope 0 at $DIR/shifts.rs:+2:34: +2:39 + StorageLive(_19); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _19 = _5; // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _20 = _19 as u128 (IntToInt); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + _21 = Lt(move _20, const 8_u128); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + assert(move _21, "attempt to shift right by `{}`, which would overflow", _19) -> [success: bb3, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + } + + bb3: { + _17 = Shr(move _18, move _19); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + StorageDead(_19); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + StorageDead(_18); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _6 = [move _7, move _12, move _17]; // scope 0 at $DIR/shifts.rs:+2:9: +2:45 + StorageDead(_17); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageDead(_12); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageDead(_7); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageLive(_22); // scope 0 at $DIR/shifts.rs:+3:9: +3:39 + StorageLive(_23); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + StorageLive(_24); // scope 0 at $DIR/shifts.rs:+3:10: +3:13 + _24 = _2; // scope 0 at $DIR/shifts.rs:+3:10: +3:13 + StorageLive(_25); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + _25 = _3; // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + _26 = _25 as u8 (IntToInt); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + _27 = Lt(move _26, const 128_u8); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + assert(move _27, "attempt to shift left by `{}`, which would overflow", _25) -> [success: bb4, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + } + + bb4: { + _23 = Shl(move _24, move _25); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + StorageDead(_25); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + StorageDead(_24); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + StorageLive(_28); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + StorageLive(_29); // scope 0 at $DIR/shifts.rs:+3:20: +3:23 + _29 = _2; // scope 0 at $DIR/shifts.rs:+3:20: +3:23 + StorageLive(_30); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + _30 = _4; // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + _31 = _30 as u32 (IntToInt); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + _32 = Lt(move _31, const 128_u32); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + assert(move _32, "attempt to shift left by `{}`, which would overflow", _30) -> [success: bb5, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + } + + bb5: { + _28 = Shl(move _29, move _30); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + StorageDead(_30); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + StorageDead(_29); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + StorageLive(_33); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + StorageLive(_34); // scope 0 at $DIR/shifts.rs:+3:30: +3:33 + _34 = _2; // scope 0 at $DIR/shifts.rs:+3:30: +3:33 + StorageLive(_35); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _35 = _5; // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _36 = _35 as u128 (IntToInt); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + _37 = Lt(move _36, const 128_u128); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + assert(move _37, "attempt to shift left by `{}`, which would overflow", _35) -> [success: bb6, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + } + + bb6: { + _33 = Shl(move _34, move _35); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + StorageDead(_35); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + StorageDead(_34); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _22 = [move _23, move _28, move _33]; // scope 0 at $DIR/shifts.rs:+3:9: +3:39 + StorageDead(_33); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + StorageDead(_28); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + StorageDead(_23); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + _0 = (move _6, move _22); // scope 0 at $DIR/shifts.rs:+1:5: +4:6 + StorageDead(_22); // scope 0 at $DIR/shifts.rs:+4:5: +4:6 + StorageDead(_6); // scope 0 at $DIR/shifts.rs:+4:5: +4:6 + return; // scope 0 at $DIR/shifts.rs:+5:2: +5:2 + } + + bb7 (cleanup): { + resume; // scope 0 at $DIR/shifts.rs:+0:1: +5:2 + } +} diff --git a/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir b/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir new file mode 100644 index 00000000000..04da2d20d24 --- /dev/null +++ b/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir @@ -0,0 +1,135 @@ +// MIR for `shift_unsigned` after built + +fn shift_unsigned(_1: u8, _2: i128, _3: u8, _4: u32, _5: u128) -> ([u8; 3], [i128; 3]) { + debug small => _1; // in scope 0 at $DIR/shifts.rs:+0:19: +0:24 + debug big => _2; // in scope 0 at $DIR/shifts.rs:+0:30: +0:33 + debug a => _3; // in scope 0 at $DIR/shifts.rs:+0:41: +0:42 + debug b => _4; // in scope 0 at $DIR/shifts.rs:+0:48: +0:49 + debug c => _5; // in scope 0 at $DIR/shifts.rs:+0:56: +0:57 + let mut _0: ([u8; 3], [i128; 3]); // return place in scope 0 at $DIR/shifts.rs:+0:68: +0:88 + let mut _6: [u8; 3]; // in scope 0 at $DIR/shifts.rs:+2:9: +2:45 + let mut _7: u8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _8: u8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:15 + let mut _9: u8; // in scope 0 at $DIR/shifts.rs:+2:19: +2:20 + let mut _10: bool; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _11: u8; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _12: u8; // in scope 0 at $DIR/shifts.rs:+2:22: +2:27 + let mut _13: u32; // in scope 0 at $DIR/shifts.rs:+2:31: +2:32 + let mut _14: bool; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _15: u8; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _16: u8; // in scope 0 at $DIR/shifts.rs:+2:34: +2:39 + let mut _17: u128; // in scope 0 at $DIR/shifts.rs:+2:43: +2:44 + let mut _18: bool; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _19: [i128; 3]; // in scope 0 at $DIR/shifts.rs:+3:9: +3:39 + let mut _20: i128; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _21: i128; // in scope 0 at $DIR/shifts.rs:+3:10: +3:13 + let mut _22: u8; // in scope 0 at $DIR/shifts.rs:+3:17: +3:18 + let mut _23: bool; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _24: i128; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _25: i128; // in scope 0 at $DIR/shifts.rs:+3:20: +3:23 + let mut _26: u32; // in scope 0 at $DIR/shifts.rs:+3:27: +3:28 + let mut _27: bool; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _28: i128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + let mut _29: i128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:33 + let mut _30: u128; // in scope 0 at $DIR/shifts.rs:+3:37: +3:38 + let mut _31: bool; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + + bb0: { + StorageLive(_6); // scope 0 at $DIR/shifts.rs:+2:9: +2:45 + StorageLive(_7); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + StorageLive(_8); // scope 0 at $DIR/shifts.rs:+2:10: +2:15 + _8 = _1; // scope 0 at $DIR/shifts.rs:+2:10: +2:15 + StorageLive(_9); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + _9 = _3; // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + _10 = Lt(_9, const 8_u8); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + assert(move _10, "attempt to shift right by `{}`, which would overflow", _9) -> [success: bb1, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + } + + bb1: { + _7 = Shr(move _8, move _9); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + StorageDead(_9); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + StorageDead(_8); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + StorageLive(_11); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + StorageLive(_12); // scope 0 at $DIR/shifts.rs:+2:22: +2:27 + _12 = _1; // scope 0 at $DIR/shifts.rs:+2:22: +2:27 + StorageLive(_13); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + _13 = _4; // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + _14 = Lt(_13, const 8_u32); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + assert(move _14, "attempt to shift right by `{}`, which would overflow", _13) -> [success: bb2, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + } + + bb2: { + _11 = Shr(move _12, move _13); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + StorageDead(_13); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + StorageDead(_12); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + StorageLive(_15); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + StorageLive(_16); // scope 0 at $DIR/shifts.rs:+2:34: +2:39 + _16 = _1; // scope 0 at $DIR/shifts.rs:+2:34: +2:39 + StorageLive(_17); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _17 = _5; // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _18 = Lt(_17, const 8_u128); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + assert(move _18, "attempt to shift right by `{}`, which would overflow", _17) -> [success: bb3, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + } + + bb3: { + _15 = Shr(move _16, move _17); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + StorageDead(_17); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + StorageDead(_16); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _6 = [move _7, move _11, move _15]; // scope 0 at $DIR/shifts.rs:+2:9: +2:45 + StorageDead(_15); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageDead(_11); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageDead(_7); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageLive(_19); // scope 0 at $DIR/shifts.rs:+3:9: +3:39 + StorageLive(_20); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + StorageLive(_21); // scope 0 at $DIR/shifts.rs:+3:10: +3:13 + _21 = _2; // scope 0 at $DIR/shifts.rs:+3:10: +3:13 + StorageLive(_22); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + _22 = _3; // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + _23 = Lt(_22, const 128_u8); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + assert(move _23, "attempt to shift left by `{}`, which would overflow", _22) -> [success: bb4, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + } + + bb4: { + _20 = Shl(move _21, move _22); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + StorageDead(_22); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + StorageDead(_21); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + StorageLive(_24); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + StorageLive(_25); // scope 0 at $DIR/shifts.rs:+3:20: +3:23 + _25 = _2; // scope 0 at $DIR/shifts.rs:+3:20: +3:23 + StorageLive(_26); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + _26 = _4; // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + _27 = Lt(_26, const 128_u32); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + assert(move _27, "attempt to shift left by `{}`, which would overflow", _26) -> [success: bb5, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + } + + bb5: { + _24 = Shl(move _25, move _26); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + StorageDead(_26); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + StorageDead(_25); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + StorageLive(_28); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + StorageLive(_29); // scope 0 at $DIR/shifts.rs:+3:30: +3:33 + _29 = _2; // scope 0 at $DIR/shifts.rs:+3:30: +3:33 + StorageLive(_30); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _30 = _5; // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _31 = Lt(_30, const 128_u128); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + assert(move _31, "attempt to shift left by `{}`, which would overflow", _30) -> [success: bb6, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + } + + bb6: { + _28 = Shl(move _29, move _30); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + StorageDead(_30); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + StorageDead(_29); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _19 = [move _20, move _24, move _28]; // scope 0 at $DIR/shifts.rs:+3:9: +3:39 + StorageDead(_28); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + StorageDead(_24); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + StorageDead(_20); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + _0 = (move _6, move _19); // scope 0 at $DIR/shifts.rs:+1:5: +4:6 + StorageDead(_19); // scope 0 at $DIR/shifts.rs:+4:5: +4:6 + StorageDead(_6); // scope 0 at $DIR/shifts.rs:+4:5: +4:6 + return; // scope 0 at $DIR/shifts.rs:+5:2: +5:2 + } + + bb7 (cleanup): { + resume; // scope 0 at $DIR/shifts.rs:+0:1: +5:2 + } +} diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff index f270ab8b69f..7e77c18d575 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff +++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff @@ -14,7 +14,6 @@ } bb1: { - StorageLive(_2); // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL _2 = begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/panic.rs:LL:COL diff --git a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff index a38c1de2a78..85dedf68ce9 100644 --- a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff @@ -12,12 +12,10 @@ let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21 scope 3 { debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21 - let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31 scope 5 { - debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31 - let _7: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22 + debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31 scope 7 { - debug _non_utf8_str => _7; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22 + debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22 } } scope 6 { @@ -52,10 +50,6 @@ + // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) } StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60 StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61 - StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31 - StorageLive(_7); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22 - StorageDead(_7); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2 - StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2 StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2 StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2 return; // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2 diff --git a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff new file mode 100644 index 00000000000..e31c2bc3938 --- /dev/null +++ b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff @@ -0,0 +1,76 @@ +- // MIR for `main` before RemoveZsts ++ // MIR for `main` after RemoveZsts + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:+0:11: +0:11 + let _1: char; // in scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22 + let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63 + let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59 + let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55 + let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73 + let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65 + scope 1 { + debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22 + let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21 + scope 3 { + debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21 + let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31 + scope 5 { +- debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31 ++ debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31 + let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22 + scope 7 { +- debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22 ++ debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22 + } + } + scope 6 { + } + } + scope 4 { + } + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22 + StorageLive(_2); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63 + _2 = InvalidChar { int: const 1114113_u32 }; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63 + _1 = (_2.1: char); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67 + StorageDead(_2); // scope 0 at $DIR/invalid_constant.rs:+6:69: +6:70 + StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21 + StorageLive(_4); // scope 1 at $DIR/invalid_constant.rs:+13:25: +13:59 + StorageLive(_5); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55 + _5 = InvalidTag { int: const 4_u32 }; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55 + _4 = (_5.1: E); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57 + _3 = [move _4]; // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60 + StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60 + StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61 +- StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31 +- StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73 ++ nop; // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31 ++ nop; // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73 + StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65 + _8 = NoVariants { int: const 0_u32 }; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65 +- _7 = (_8.1: Empty); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71 +- _6 = [move _7]; // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74 +- StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74 ++ nop; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71 ++ nop; // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74 ++ nop; // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74 + StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75 +- StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22 +- _0 = const (); // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2 +- StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2 +- StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2 ++ nop; // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22 ++ nop; // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2 ++ nop; // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2 ++ nop; // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2 + StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2 + StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2 + return; // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2 + } + } + diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs index 0337a7ca851..eb6172cdff9 100644 --- a/tests/mir-opt/const_prop/invalid_constant.rs +++ b/tests/mir-opt/const_prop/invalid_constant.rs @@ -11,6 +11,7 @@ enum E { A, B, C } #[derive(Copy, Clone)] enum Empty {} +// EMIT_MIR invalid_constant.main.RemoveZsts.diff // EMIT_MIR invalid_constant.main.ConstProp.diff fn main() { // An invalid char. diff --git a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff index 964dd308074..a4f9003e140 100644 --- a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff @@ -5,14 +5,10 @@ let mut _0: (); // return place in scope 0 at $DIR/issue_66971.rs:+0:11: +0:11 let _1: (); // in scope 0 at $DIR/issue_66971.rs:+1:5: +1:23 let mut _2: ((), u8, u8); // in scope 0 at $DIR/issue_66971.rs:+1:12: +1:22 - let mut _3: (); // in scope 0 at $DIR/issue_66971.rs:+1:13: +1:15 bb0: { - StorageLive(_1); // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23 StorageLive(_2); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22 - StorageLive(_3); // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15 - _2 = (move _3, const 0_u8, const 0_u8); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22 - StorageDead(_3); // scope 0 at $DIR/issue_66971.rs:+1:21: +1:22 + _2 = (const (), const 0_u8, const 0_u8); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22 _1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23 // mir::Constant // + span: $DIR/issue_66971.rs:17:5: 17:11 @@ -21,7 +17,6 @@ bb1: { StorageDead(_2); // scope 0 at $DIR/issue_66971.rs:+1:22: +1:23 - StorageDead(_1); // scope 0 at $DIR/issue_66971.rs:+1:23: +1:24 return; // scope 0 at $DIR/issue_66971.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff index a631cb31090..f456a321204 100644 --- a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff @@ -8,7 +8,6 @@ let mut _3: (u8, u8); // in scope 0 at $DIR/issue_67019.rs:+1:11: +1:17 bb0: { - StorageLive(_1); // scope 0 at $DIR/issue_67019.rs:+1:5: +1:20 StorageLive(_2); // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19 StorageLive(_3); // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17 - _3 = (const 1_u8, const 2_u8); // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17 @@ -23,7 +22,6 @@ bb1: { StorageDead(_2); // scope 0 at $DIR/issue_67019.rs:+1:19: +1:20 - StorageDead(_1); // scope 0 at $DIR/issue_67019.rs:+1:20: +1:21 return; // scope 0 at $DIR/issue_67019.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff index 22f710387db..1151caaabbc 100644 --- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff @@ -12,7 +12,6 @@ bb0: { _1 = const 1_u32; // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14 - StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 - _2 = consume(_1) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 + _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 // mir::Constant @@ -21,7 +20,6 @@ } bb1: { - StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16 return; // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2 } } diff --git a/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff new file mode 100644 index 00000000000..933dfbb5166 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff @@ -0,0 +1,15 @@ +- // MIR for `from_char` before ConstProp ++ // MIR for `from_char` after ConstProp + + fn from_char() -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/transmute.rs:+0:23: +0:26 + scope 1 { + } + + bb0: { +- _0 = const 'R' as i32 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:28 ++ _0 = const 82_i32; // scope 1 at $DIR/transmute.rs:+1:14: +1:28 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff new file mode 100644 index 00000000000..f3474855f02 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff @@ -0,0 +1,14 @@ +- // MIR for `invalid_bool` before ConstProp ++ // MIR for `invalid_bool` after ConstProp + + fn invalid_bool() -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37 + scope 1 { + } + + bb0: { + _0 = const -1_i8 as bool (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:30 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff new file mode 100644 index 00000000000..ba087e226c9 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff @@ -0,0 +1,14 @@ +- // MIR for `invalid_char` before ConstProp ++ // MIR for `invalid_char` after ConstProp + + fn invalid_char() -> char { + let mut _0: char; // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37 + scope 1 { + } + + bb0: { + _0 = const _ as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff new file mode 100644 index 00000000000..76d464789c1 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `less_as_i8` before ConstProp ++ // MIR for `less_as_i8` after ConstProp + + fn less_as_i8() -> i8 { + let mut _0: i8; // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:26 + let mut _1: std::cmp::Ordering; // in scope 0 at $DIR/transmute.rs:+1:24: +1:48 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/transmute.rs:+1:24: +1:48 +- _1 = Less; // scope 1 at $DIR/transmute.rs:+1:24: +1:48 +- _0 = move _1 as i8 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:49 ++ _1 = const Less; // scope 1 at $DIR/transmute.rs:+1:24: +1:48 ++ // mir::Constant ++ // + span: no-location ++ // + literal: Const { ty: std::cmp::Ordering, val: Value(Scalar(0xff)) } ++ _0 = const -1_i8; // scope 1 at $DIR/transmute.rs:+1:14: +1:49 + StorageDead(_1); // scope 1 at $DIR/transmute.rs:+1:48: +1:49 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.rs b/tests/mir-opt/const_prop/transmute.rs new file mode 100644 index 00000000000..b753cdccd60 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.rs @@ -0,0 +1,61 @@ +// unit-test: ConstProp +// compile-flags: -O --crate-type=lib + +use std::mem::transmute; + +// EMIT_MIR transmute.less_as_i8.ConstProp.diff +pub fn less_as_i8() -> i8 { + unsafe { transmute(std::cmp::Ordering::Less) } +} + +// EMIT_MIR transmute.from_char.ConstProp.diff +pub fn from_char() -> i32 { + unsafe { transmute('R') } +} + +// EMIT_MIR transmute.valid_char.ConstProp.diff +pub fn valid_char() -> char { + unsafe { transmute(0x52_u32) } +} + +// EMIT_MIR transmute.invalid_char.ConstProp.diff +pub unsafe fn invalid_char() -> char { + unsafe { transmute(i32::MAX) } +} + +// EMIT_MIR transmute.invalid_bool.ConstProp.diff +pub unsafe fn invalid_bool() -> bool { + unsafe { transmute(-1_i8) } +} + +// EMIT_MIR transmute.undef_union_as_integer.ConstProp.diff +pub unsafe fn undef_union_as_integer() -> u32 { + union Union32 { value: u32, unit: () } + unsafe { transmute(Union32 { unit: () }) } +} + +// EMIT_MIR transmute.unreachable_direct.ConstProp.diff +pub unsafe fn unreachable_direct() -> ! { + let x: Never = unsafe { transmute(()) }; + match x {} +} + +// EMIT_MIR transmute.unreachable_ref.ConstProp.diff +pub unsafe fn unreachable_ref() -> ! { + let x: &Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_mut.ConstProp.diff +pub unsafe fn unreachable_mut() -> ! { + let x: &mut Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_box.ConstProp.diff +pub unsafe fn unreachable_box() -> ! { + let x: Box<Never> = unsafe { transmute(1_usize) }; + match *x {} +} + +enum Never {} diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff new file mode 100644 index 00000000000..538b1f26e4c --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff @@ -0,0 +1,22 @@ +- // MIR for `undef_union_as_integer` before ConstProp ++ // MIR for `undef_union_as_integer` after ConstProp + + fn undef_union_as_integer() -> u32 { + let mut _0: u32; // return place in scope 0 at $DIR/transmute.rs:+0:43: +0:46 + let mut _1: undef_union_as_integer::Union32; // in scope 0 at $DIR/transmute.rs:+2:24: +2:44 + let mut _2: (); // in scope 0 at $DIR/transmute.rs:+2:40: +2:42 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/transmute.rs:+2:24: +2:44 + StorageLive(_2); // scope 1 at $DIR/transmute.rs:+2:40: +2:42 + _2 = (); // scope 1 at $DIR/transmute.rs:+2:40: +2:42 + _1 = Union32 { value: move _2 }; // scope 1 at $DIR/transmute.rs:+2:24: +2:44 + StorageDead(_2); // scope 1 at $DIR/transmute.rs:+2:43: +2:44 + _0 = move _1 as u32 (Transmute); // scope 1 at $DIR/transmute.rs:+2:14: +2:45 + StorageDead(_1); // scope 1 at $DIR/transmute.rs:+2:44: +2:45 + return; // scope 0 at $DIR/transmute.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff new file mode 100644 index 00000000000..8bf97996a67 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `unreachable_box` before ConstProp ++ // MIR for `unreachable_box` after ConstProp + + fn unreachable_box() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff new file mode 100644 index 00000000000..81b7b368993 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff @@ -0,0 +1,25 @@ +- // MIR for `unreachable_direct` before ConstProp ++ // MIR for `unreachable_direct` after ConstProp + + fn unreachable_direct() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:41: +3:2 + let _2: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 + let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:15 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:41: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_3); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _3 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + unreachable; // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff new file mode 100644 index 00000000000..34f7aea8ed2 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff @@ -0,0 +1,27 @@ +- // MIR for `unreachable_mut` before ConstProp ++ // MIR for `unreachable_mut` after ConstProp + + fn unreachable_mut() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 + let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + _3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + _2 = &mut (*_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + StorageDead(_3); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 + StorageLive(_4); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff new file mode 100644 index 00000000000..ff95f2a0b94 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `unreachable_ref` before ConstProp ++ // MIR for `unreachable_ref` after ConstProp + + fn unreachable_ref() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + _2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff new file mode 100644 index 00000000000..eac33b73003 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff @@ -0,0 +1,15 @@ +- // MIR for `valid_char` before ConstProp ++ // MIR for `valid_char` after ConstProp + + fn valid_char() -> char { + let mut _0: char; // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:28 + scope 1 { + } + + bb0: { +- _0 = const 82_u32 as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33 ++ _0 = const 'R'; // scope 1 at $DIR/transmute.rs:+1:14: +1:33 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff index 270a1ccf560..d370abce45a 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff @@ -13,7 +13,6 @@ bb0: { - _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19 + _1 = const (1_u32, 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19 - StorageLive(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15 _2 = consume(_1) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15 // mir::Constant // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12 @@ -21,7 +20,6 @@ } bb1: { - StorageDead(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16 return; // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2 } } diff --git a/tests/mir-opt/inline/asm_unwind.main.Inline.diff b/tests/mir-opt/inline/asm_unwind.main.Inline.diff index f1b62ac38ba..ed290063a93 100644 --- a/tests/mir-opt/inline/asm_unwind.main.Inline.diff +++ b/tests/mir-opt/inline/asm_unwind.main.Inline.diff @@ -7,7 +7,7 @@ + scope 1 (inlined foo) { // at $DIR/asm_unwind.rs:21:5: 21:10 + let _2: D; // in scope 1 at $DIR/asm_unwind.rs:15:9: 15:11 + scope 2 { -+ debug _d => _2; // in scope 2 at $DIR/asm_unwind.rs:15:9: 15:11 ++ debug _d => const D; // in scope 2 at $DIR/asm_unwind.rs:15:9: 15:11 + scope 3 { + } + } @@ -19,21 +19,21 @@ - // mir::Constant - // + span: $DIR/asm_unwind.rs:21:5: 21:8 - // + literal: Const { ty: fn() {foo}, val: Value(<ZST>) } -+ StorageLive(_2); // scope 1 at $DIR/asm_unwind.rs:15:9: 15:11 -+ asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb3]; // scope 3 at $DIR/asm_unwind.rs:16:14: 16:54 ++ StorageLive(_2); // scope 0 at $DIR/asm_unwind.rs:+1:5: +1:10 ++ asm!("", options(MAY_UNWIND)) -> [return: bb2, unwind: bb3]; // scope 3 at $DIR/asm_unwind.rs:16:14: 16:54 } bb1: { -+ drop(_2) -> bb2; // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2 -+ } -+ -+ bb2: { -+ StorageDead(_2); // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2 ++ StorageDead(_2); // scope 0 at $DIR/asm_unwind.rs:+1:5: +1:10 StorageDead(_1); // scope 0 at $DIR/asm_unwind.rs:+1:10: +1:11 _0 = const (); // scope 0 at $DIR/asm_unwind.rs:+0:15: +2:2 return; // scope 0 at $DIR/asm_unwind.rs:+2:2: +2:2 + } + ++ bb2: { ++ drop(_2) -> bb1; // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2 ++ } ++ + bb3 (cleanup): { + drop(_2) -> bb4; // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2 + } diff --git a/tests/mir-opt/inline/cycle.g.Inline.diff b/tests/mir-opt/inline/cycle.g.Inline.diff index 5f3ee467c88..20d313aecf5 100644 --- a/tests/mir-opt/inline/cycle.g.Inline.diff +++ b/tests/mir-opt/inline/cycle.g.Inline.diff @@ -5,11 +5,11 @@ let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:8: +0:8 let _1: (); // in scope 0 at $DIR/cycle.rs:+1:5: +1:12 + let mut _2: fn() {main}; // in scope 0 at $DIR/cycle.rs:+1:5: +1:12 ++ let mut _5: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 + scope 1 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12 + debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 + let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 -+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 + } + } @@ -25,14 +25,16 @@ - // mir::Constant // + span: $DIR/cycle.rs:12:7: 12:11 // + literal: Const { ty: fn() {main}, val: Value(<ZST>) } -+ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 + StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 + _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ _5 = const (); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { ++ StorageDead(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 + StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 StorageDead(_1); // scope 0 at $DIR/cycle.rs:+1:12: +1:13 _0 = const (); // scope 0 at $DIR/cycle.rs:+0:8: +2:2 @@ -48,9 +50,8 @@ + } + + bb4: { -+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 -+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 + drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/tests/mir-opt/inline/cycle.main.Inline.diff b/tests/mir-opt/inline/cycle.main.Inline.diff index 6b4c63bbd91..dacc5f4be9d 100644 --- a/tests/mir-opt/inline/cycle.main.Inline.diff +++ b/tests/mir-opt/inline/cycle.main.Inline.diff @@ -5,11 +5,11 @@ let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11 let _1: (); // in scope 0 at $DIR/cycle.rs:+1:5: +1:9 + let mut _2: fn() {g}; // in scope 0 at $DIR/cycle.rs:+1:5: +1:9 ++ let mut _5: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 + scope 1 (inlined f::<fn() {g}>) { // at $DIR/cycle.rs:17:5: 17:9 + debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 + let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 -+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8 + } + } @@ -25,14 +25,16 @@ - // mir::Constant // + span: $DIR/cycle.rs:17:7: 17:8 // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } -+ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 + StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 + _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ _5 = const (); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { ++ StorageDead(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 + StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 StorageDead(_1); // scope 0 at $DIR/cycle.rs:+1:9: +1:10 _0 = const (); // scope 0 at $DIR/cycle.rs:+0:11: +2:2 @@ -48,9 +50,8 @@ + } + + bb4: { -+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 -+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 + drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/tests/mir-opt/inline/exponential_runtime.main.Inline.diff b/tests/mir-opt/inline/exponential_runtime.main.Inline.diff index 7fd62be7ab9..dd1f253cb47 100644 --- a/tests/mir-opt/inline/exponential_runtime.main.Inline.diff +++ b/tests/mir-opt/inline/exponential_runtime.main.Inline.diff @@ -18,9 +18,13 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 - _1 = <() as G>::call() -> bb1; // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 -+ StorageLive(_2); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 -+ StorageLive(_5); // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25 -+ _5 = <() as E>::call() -> bb3; // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25 ++ StorageLive(_2); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 ++ StorageLive(_3); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 ++ StorageLive(_4); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 ++ StorageLive(_5); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 ++ StorageLive(_6); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 ++ StorageLive(_7); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 ++ _5 = <() as E>::call() -> bb4; // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25 // mir::Constant - // + span: $DIR/exponential_runtime.rs:86:5: 86:20 - // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) } @@ -29,47 +33,43 @@ } bb1: { -+ StorageDead(_3); // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26 -+ StorageLive(_4); // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25 -+ _4 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25 -+ // mir::Constant -+ // + span: $DIR/exponential_runtime.rs:75:9: 75:23 -+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) } -+ } -+ -+ bb2: { -+ StorageDead(_4); // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26 ++ StorageDead(_4); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 ++ StorageDead(_3); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 ++ StorageDead(_2); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 StorageDead(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23 _0 = const (); // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2 return; // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2 + } + ++ bb2: { ++ StorageDead(_7); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 ++ StorageDead(_6); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 ++ StorageDead(_5); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25 ++ _3 = <() as F>::call() -> bb3; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25 ++ // mir::Constant ++ // + span: $DIR/exponential_runtime.rs:74:9: 74:23 ++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) } ++ } ++ + bb3: { -+ StorageDead(_5); // scope 2 at $DIR/exponential_runtime.rs:61:25: 61:26 -+ StorageLive(_6); // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25 -+ _6 = <() as E>::call() -> bb4; // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25 ++ _4 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25 + // mir::Constant -+ // + span: $DIR/exponential_runtime.rs:62:9: 62:23 -+ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) } ++ // + span: $DIR/exponential_runtime.rs:75:9: 75:23 ++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) } + } + + bb4: { -+ StorageDead(_6); // scope 2 at $DIR/exponential_runtime.rs:62:25: 62:26 -+ StorageLive(_7); // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25 -+ _7 = <() as E>::call() -> bb5; // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25 ++ _6 = <() as E>::call() -> bb5; // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25 + // mir::Constant -+ // + span: $DIR/exponential_runtime.rs:63:9: 63:23 ++ // + span: $DIR/exponential_runtime.rs:62:9: 62:23 + // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) } + } + + bb5: { -+ StorageDead(_7); // scope 2 at $DIR/exponential_runtime.rs:63:25: 63:26 -+ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26 -+ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25 -+ _3 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25 ++ _7 = <() as E>::call() -> bb2; // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25 + // mir::Constant -+ // + span: $DIR/exponential_runtime.rs:74:9: 74:23 -+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) } ++ // + span: $DIR/exponential_runtime.rs:63:9: 63:23 ++ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) } } } diff --git a/tests/mir-opt/inline/inline_cycle.two.Inline.diff b/tests/mir-opt/inline/inline_cycle.two.Inline.diff index 64c0065b543..0215b3d93f9 100644 --- a/tests/mir-opt/inline/inline_cycle.two.Inline.diff +++ b/tests/mir-opt/inline/inline_cycle.two.Inline.diff @@ -5,10 +5,10 @@ let mut _0: (); // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10 let _1: (); // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12 + let mut _2: fn() {f}; // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12 ++ let mut _4: (); // in scope 0 at $DIR/inline_cycle.rs:54:5: 54:8 + scope 1 (inlined call::<fn() {f}>) { // at $DIR/inline_cycle.rs:49:5: 49:12 + debug f => _2; // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23 + let _3: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 -+ let mut _4: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 + scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8 + } + } @@ -24,14 +24,15 @@ - // mir::Constant // + span: $DIR/inline_cycle.rs:49:10: 49:11 // + literal: Const { ty: fn() {f}, val: Value(<ZST>) } -+ StorageLive(_3); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 ++ StorageLive(_3); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12 + StorageLive(_4); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 ++ _4 = const (); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 + _3 = move _2() -> bb1; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { -+ StorageDead(_4); // scope 1 at $DIR/inline_cycle.rs:54:7: 54:8 -+ StorageDead(_3); // scope 1 at $DIR/inline_cycle.rs:54:8: 54:9 ++ StorageDead(_4); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 ++ StorageDead(_3); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12 + StorageDead(_2); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12 StorageDead(_1); // scope 0 at $DIR/inline_cycle.rs:+1:12: +1:13 _0 = const (); // scope 0 at $DIR/inline_cycle.rs:+0:10: +2:2 diff --git a/tests/mir-opt/inline/inline_diverging.g.Inline.diff b/tests/mir-opt/inline/inline_diverging.g.Inline.diff index b787a19f4b2..4f22ad43700 100644 --- a/tests/mir-opt/inline/inline_diverging.g.Inline.diff +++ b/tests/mir-opt/inline/inline_diverging.g.Inline.diff @@ -34,7 +34,7 @@ bb2: { StorageLive(_6); // scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16 - _6 = panic(); // scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16 -+ StorageLive(_7); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL ++ StorageLive(_7); // scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16 + _7 = begin_panic::<&str>(const "explicit panic"); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL // mir::Constant - // + span: $DIR/inline_diverging.rs:16:9: 16:14 diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.diff index e1b2f7dbf35..31208e0052c 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.diff @@ -5,19 +5,18 @@ let mut _0: (); // return place in scope 0 at $DIR/inline_diverging.rs:+0:12: +0:12 let _1: (!, !); // in scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22 + let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22 ++ let mut _8: (); // in scope 0 at $DIR/inline_diverging.rs:27:13: 27:16 + scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline_diverging.rs:22:5: 22:22 + debug f => _2; // in scope 1 at $DIR/inline_diverging.rs:26:36: 26:37 + let _3: !; // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 + let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 -+ let mut _5: (); // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 -+ let mut _6: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:14 -+ let mut _7: (); // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:16 -+ let mut _8: !; // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7 -+ let mut _9: !; // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10 ++ let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:14 ++ let mut _6: !; // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7 ++ let mut _7: !; // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10 + scope 2 { + debug a => _3; // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10 + scope 3 { -+ debug b => _9; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10 ++ debug b => _7; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10 + } + } + scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16 @@ -35,21 +34,21 @@ - // mir::Constant // + span: $DIR/inline_diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) } -+ StorageLive(_9); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22 ++ StorageLive(_7); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22 + StorageLive(_3); // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 + StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 + _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 -+ StorageLive(_5); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 ++ StorageLive(_8); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 ++ _8 = const (); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 + _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL + } + + bb1: { -+ StorageDead(_7); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16 -+ StorageDead(_6); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16 -+ StorageLive(_8); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 -+ _8 = move _3; // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 -+ _1 = (move _8, move _9); // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 -+ StorageDead(_8); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11 ++ StorageDead(_5); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16 ++ StorageLive(_6); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 ++ _6 = move _3; // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 ++ _1 = (move _6, move _7); // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 ++ StorageDead(_6); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11 + StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 + drop(_2) -> bb2; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 + } @@ -71,12 +70,11 @@ + } + + bb6: { -+ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16 ++ StorageDead(_8); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 + StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16 -+ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 -+ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 -+ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 -+ _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 ++ StorageLive(_5); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 ++ _5 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 ++ _7 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 + // mir::Constant + // + span: $DIR/inline_diverging.rs:28:13: 28:14 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) } diff --git a/tests/mir-opt/inline/inline_options.main.Inline.after.mir b/tests/mir-opt/inline/inline_options.main.Inline.after.mir index 1c590be945c..abe26bd8ce3 100644 --- a/tests/mir-opt/inline/inline_options.main.Inline.after.mir +++ b/tests/mir-opt/inline/inline_options.main.Inline.after.mir @@ -21,35 +21,35 @@ fn main() -> () { bb1: { StorageDead(_1); // scope 0 at $DIR/inline_options.rs:+1:18: +1:19 StorageLive(_2); // scope 0 at $DIR/inline_options.rs:+2:5: +2:21 - StorageLive(_3); // scope 1 at $DIR/inline_options.rs:16:23: 16:26 - _3 = g() -> bb2; // scope 1 at $DIR/inline_options.rs:16:23: 16:26 + StorageLive(_3); // scope 0 at $DIR/inline_options.rs:+2:5: +2:21 + StorageLive(_4); // scope 0 at $DIR/inline_options.rs:+2:5: +2:21 + StorageLive(_5); // scope 0 at $DIR/inline_options.rs:+2:5: +2:21 + _3 = g() -> bb3; // scope 1 at $DIR/inline_options.rs:16:23: 16:26 // mir::Constant // + span: $DIR/inline_options.rs:16:23: 16:24 // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } } bb2: { - StorageDead(_3); // scope 1 at $DIR/inline_options.rs:16:26: 16:27 - StorageLive(_4); // scope 1 at $DIR/inline_options.rs:16:28: 16:31 - _4 = g() -> bb3; // scope 1 at $DIR/inline_options.rs:16:28: 16:31 - // mir::Constant - // + span: $DIR/inline_options.rs:16:28: 16:29 - // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } + StorageDead(_5); // scope 0 at $DIR/inline_options.rs:+2:5: +2:21 + StorageDead(_4); // scope 0 at $DIR/inline_options.rs:+2:5: +2:21 + StorageDead(_3); // scope 0 at $DIR/inline_options.rs:+2:5: +2:21 + StorageDead(_2); // scope 0 at $DIR/inline_options.rs:+2:21: +2:22 + _0 = const (); // scope 0 at $DIR/inline_options.rs:+0:11: +3:2 + return; // scope 0 at $DIR/inline_options.rs:+3:2: +3:2 } bb3: { - StorageDead(_4); // scope 1 at $DIR/inline_options.rs:16:31: 16:32 - StorageLive(_5); // scope 1 at $DIR/inline_options.rs:16:33: 16:36 - _5 = g() -> bb4; // scope 1 at $DIR/inline_options.rs:16:33: 16:36 + _4 = g() -> bb4; // scope 1 at $DIR/inline_options.rs:16:28: 16:31 // mir::Constant - // + span: $DIR/inline_options.rs:16:33: 16:34 + // + span: $DIR/inline_options.rs:16:28: 16:29 // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } } bb4: { - StorageDead(_5); // scope 1 at $DIR/inline_options.rs:16:36: 16:37 - StorageDead(_2); // scope 0 at $DIR/inline_options.rs:+2:21: +2:22 - _0 = const (); // scope 0 at $DIR/inline_options.rs:+0:11: +3:2 - return; // scope 0 at $DIR/inline_options.rs:+3:2: +3:2 + _5 = g() -> bb2; // scope 1 at $DIR/inline_options.rs:16:33: 16:36 + // mir::Constant + // + span: $DIR/inline_options.rs:16:33: 16:34 + // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } } } diff --git a/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir index 4dd1aad489d..a98c294cacb 100644 --- a/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir +++ b/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir @@ -10,10 +10,9 @@ fn main() -> () { scope 1 { debug f => _1; // in scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:9: +1:10 scope 2 (inlined main::{closure#0}) { // at $DIR/issue_76997_inline_scopes_parenting.rs:6:5: 6:10 - debug x => _5; // in scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:14: +1:15 - let _6: (); // in scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24 + debug x => const (); // in scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:14: +1:15 scope 3 { - debug y => _6; // in scope 3 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24 + debug y => const (); // in scope 3 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24 } } } @@ -36,8 +35,6 @@ fn main() -> () { _3 = (move _4,); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10 StorageLive(_5); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10 _5 = move (_3.0: ()); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10 - StorageLive(_6); // scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24 - StorageDead(_6); // scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:32: +1:33 StorageDead(_5); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10 StorageDead(_4); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:9: +2:10 StorageDead(_3); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:9: +2:10 diff --git a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff index 8ff64c1ea15..7031c3f3e69 100644 --- a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff +++ b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff @@ -8,7 +8,7 @@ let _3: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60 bb0: { - StorageLive(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46 _1 = assert_inhabited::<T>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46 // mir::Constant // + span: $DIR/intrinsic_asserts.rs:25:5: 25:44 @@ -16,8 +16,8 @@ } bb1: { - StorageDead(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:46: +1:47 - StorageLive(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+1:46: +1:47 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47 _2 = assert_zero_valid::<T>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47 // mir::Constant // + span: $DIR/intrinsic_asserts.rs:26:5: 26:45 @@ -25,8 +25,8 @@ } bb2: { - StorageDead(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:47: +2:48 - StorageLive(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+2:47: +2:48 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60 _3 = assert_mem_uninitialized_valid::<T>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60 // mir::Constant // + span: $DIR/intrinsic_asserts.rs:27:5: 27:58 @@ -34,7 +34,7 @@ } bb3: { - StorageDead(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:60: +3:61 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+3:60: +3:61 nop; // scope 0 at $DIR/intrinsic_asserts.rs:+0:21: +4:2 return; // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2 } diff --git a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff index ddc01590315..4caa9971fef 100644 --- a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff +++ b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff @@ -8,7 +8,7 @@ let _3: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 bb0: { - StorageLive(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50 - _1 = assert_inhabited::<Never>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50 + _1 = assert_inhabited::<Never>(); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50 // mir::Constant @@ -17,8 +17,8 @@ } bb1: { - StorageDead(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:50: +1:51 - StorageLive(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+1:50: +1:51 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49 - _2 = assert_zero_valid::<&u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49 + _2 = assert_zero_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49 // mir::Constant @@ -28,8 +28,8 @@ } bb2: { - StorageDead(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:49: +2:50 - StorageLive(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+2:49: +2:50 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 - _3 = assert_mem_uninitialized_valid::<&u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 + _3 = assert_mem_uninitialized_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 // mir::Constant @@ -39,7 +39,7 @@ } bb3: { - StorageDead(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:62: +3:63 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+3:62: +3:63 nop; // scope 0 at $DIR/intrinsic_asserts.rs:+0:17: +4:2 return; // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2 } diff --git a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff index 568fbf1a0d6..b0bec957369 100644 --- a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff +++ b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff @@ -8,7 +8,7 @@ let _3: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61 bb0: { - StorageLive(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47 - _1 = assert_inhabited::<()>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47 - // mir::Constant - // + span: $DIR/intrinsic_asserts.rs:7:5: 7:45 @@ -17,8 +17,8 @@ } bb1: { - StorageDead(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:47: +1:48 - StorageLive(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+1:47: +1:48 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48 - _2 = assert_zero_valid::<u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48 - // mir::Constant - // + span: $DIR/intrinsic_asserts.rs:8:5: 8:46 @@ -27,8 +27,8 @@ } bb2: { - StorageDead(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:48: +2:49 - StorageLive(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+2:48: +2:49 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61 - _3 = assert_mem_uninitialized_valid::<u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61 - // mir::Constant - // + span: $DIR/intrinsic_asserts.rs:9:5: 9:59 @@ -37,7 +37,7 @@ } bb3: { - StorageDead(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:61: +3:62 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+3:61: +3:62 nop; // scope 0 at $DIR/intrinsic_asserts.rs:+0:20: +4:2 return; // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2 } diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff index fb0b3866e69..b377a65b964 100644 --- a/tests/mir-opt/issue_101973.inner.ConstProp.diff +++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff @@ -12,9 +12,9 @@ let mut _7: u32; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 let mut _8: u32; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 let mut _9: u32; // in scope 0 at $DIR/issue_101973.rs:+1:33: +1:39 - let mut _10: i32; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 + let mut _10: u32; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 let mut _11: bool; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 - let mut _12: i32; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 + let mut _12: u32; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 let mut _13: bool; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 scope 1 (inlined imm8) { // at $DIR/issue_101973.rs:14:5: 14:17 debug x => _1; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14 @@ -43,24 +43,24 @@ StorageLive(_6); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 StorageLive(_7); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageLive(_8); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -- _10 = BitAnd(const 8_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -- _11 = Ne(move _10, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -- assert(!move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -+ _10 = const 0_i32; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -+ _11 = const false; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -+ assert(!const false, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 +- _10 = const 8_i32 as u32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 +- _11 = Lt(move _10, const 32_u32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 +- assert(move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 ++ _10 = const 8_u32; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 ++ _11 = const true; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 ++ assert(const true, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 } bb1: { _8 = Shr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageDead(_8); // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52 -- _12 = BitAnd(const 1_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -- _13 = Ne(move _12, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -- assert(!move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -+ _12 = const 0_i32; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -+ _13 = const false; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -+ assert(!const false, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 +- _12 = const 1_i32 as u32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 +- _13 = Lt(move _12, const 32_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 +- assert(move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 ++ _12 = const 1_u32; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 ++ _13 = const true; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 ++ assert(const true, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 } bb2: { diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff index cc4f7cc0699..abb89b91dd3 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -42,7 +42,6 @@ } bb1: { - StorageLive(_15); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL _15 = core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/panic.rs:LL:COL diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index 291fc5063d2..6e28fb61b6b 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -66,7 +66,6 @@ fn num_to_digit(_1: char) -> u32 { } bb6: { - StorageLive(_8); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL _8 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value"); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index bcda1288045..8e6e6fc0ec2 100644 --- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -24,61 +24,49 @@ StorageLive(_2); // scope 0 at $DIR/issue_75439.rs:+2:9: +2:15 StorageLive(_3); // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52 _3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52 - _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53 - // mir::Constant - // + span: $DIR/issue_75439.rs:8:37: 8:46 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) } + _2 = move _3 as [u32; 4] (Transmute); // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53 + StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53 + switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb1: { - StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53 - switchInt(_2[0 of 4]) -> [0: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb2: { - switchInt(_2[1 of 4]) -> [0: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + switchInt(_2[2 of 4]) -> [0: bb4, 4294901760: bb5, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb3: { - switchInt(_2[2 of 4]) -> [0: bb5, 4294901760: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 - } - - bb4: { StorageLive(_5); // scope 3 at $DIR/issue_75439.rs:+5:14: +5:38 StorageLive(_6); // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35 _6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35 - _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36 - // mir::Constant - // + span: $DIR/issue_75439.rs:11:23: 11:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) } + _5 = move _6 as [u8; 4] (Transmute); // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36 + StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36 + _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39 + StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39 + StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6 + goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 } - bb5: { + bb4: { StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 _4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 - goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } - bb6: { + bb5: { StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 _4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 - goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } - bb7: { - StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36 - _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39 - StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39 - StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6 - goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 - } - - bb8: { + bb6: { _0 = Option::<[u8; 4]>::None; // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13 - goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 + goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 } - bb9: { + bb7: { StorageDead(_2); // scope 0 at $DIR/issue_75439.rs:+9:1: +9:2 return; // scope 0 at $DIR/issue_75439.rs:+9:2: +9:2 } diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff index d9898d8e0f0..5c5a9e90a9d 100644 --- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff @@ -11,7 +11,7 @@ StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:72:9: 72:32 +- // + span: $DIR/lower_intrinsics.rs:105:9: 105:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) } + assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 diff --git a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index d962ef8cb12..87960521bb4 100644 --- a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -31,7 +31,7 @@ _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:49:5: 49:41 +- // + span: $DIR/lower_intrinsics.rs:82:5: 82:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) } + _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 @@ -46,13 +46,13 @@ StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _19 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:50:42: 50:44 + // + span: $DIR/lower_intrinsics.rs:83:42: 83:44 // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) } _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:50:5: 50:41 +- // + span: $DIR/lower_intrinsics.rs:83:5: 83:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) } + _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 @@ -67,13 +67,13 @@ StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _18 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:51:42: 51:45 + // + span: $DIR/lower_intrinsics.rs:84:42: 84:45 // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) } _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:51:5: 51:41 +- // + span: $DIR/lower_intrinsics.rs:84:5: 84:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) } + _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 + goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 @@ -88,13 +88,13 @@ StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _17 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:52:42: 52:47 + // + span: $DIR/lower_intrinsics.rs:85:42: 85:47 // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) } _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:52:5: 52:41 +- // + span: $DIR/lower_intrinsics.rs:85:5: 85:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) } + _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 + goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff index 5c972a00e46..15cce7f4a2c 100644 --- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff @@ -49,7 +49,7 @@ StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91 - _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:65:9: 65:28 +- // + span: $DIR/lower_intrinsics.rs:98:9: 98:28 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) } + copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 diff --git a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff new file mode 100644 index 00000000000..c563703b250 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff @@ -0,0 +1,54 @@ +- // MIR for `option_payload` before LowerIntrinsics ++ // MIR for `option_payload` after LowerIntrinsics + + fn option_payload(_1: &Option<usize>, _2: &Option<String>) -> () { + debug o => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:23: +0:24 + debug p => _2; // in scope 0 at $DIR/lower_intrinsics.rs:+0:42: +0:43 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:62: +0:62 + let mut _4: *const std::option::Option<usize>; // in scope 0 at $DIR/lower_intrinsics.rs:+2:55: +2:56 + let mut _6: *const std::option::Option<std::string::String>; // in scope 0 at $DIR/lower_intrinsics.rs:+3:55: +3:56 + scope 1 { + let _3: *const usize; // in scope 1 at $DIR/lower_intrinsics.rs:+2:13: +2:15 + scope 2 { + debug _x => _3; // in scope 2 at $DIR/lower_intrinsics.rs:+2:13: +2:15 + let _5: *const std::string::String; // in scope 2 at $DIR/lower_intrinsics.rs:+3:13: +3:15 + scope 3 { + debug _y => _5; // in scope 3 at $DIR/lower_intrinsics.rs:+3:13: +3:15 + } + } + } + + bb0: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:13: +2:15 + StorageLive(_4); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56 + _4 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56 +- _3 = option_payload_ptr::<usize>(move _4) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:132:18: 132:54 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<usize>) -> *const usize {option_payload_ptr::<usize>}, val: Value(<ZST>) } ++ _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 + } + + bb1: { + StorageDead(_4); // scope 1 at $DIR/lower_intrinsics.rs:+2:56: +2:57 + StorageLive(_5); // scope 2 at $DIR/lower_intrinsics.rs:+3:13: +3:15 + StorageLive(_6); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56 + _6 = &raw const (*_2); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56 +- _5 = option_payload_ptr::<String>(move _6) -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:133:18: 133:54 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<String>) -> *const String {option_payload_ptr::<String>}, val: Value(<ZST>) } ++ _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 ++ goto -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 + } + + bb2: { + StorageDead(_6); // scope 2 at $DIR/lower_intrinsics.rs:+3:56: +3:57 + _0 = const (); // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +4:6 + StorageDead(_5); // scope 2 at $DIR/lower_intrinsics.rs:+4:5: +4:6 + StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:+4:5: +4:6 + return; // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff index 27fceeedf6e..f2f676843b2 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::<i32>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:85:14: 85:45 +- // + span: $DIR/lower_intrinsics.rs:118:14: 118:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::<i32>}, val: Value(<ZST>) } + _0 = (*_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff index 610c67d2fec..3ad21283fa4 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::<Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:90:14: 90:45 +- // + span: $DIR/lower_intrinsics.rs:123:14: 123:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::<Never>}, val: Value(<ZST>) } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 } diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index a0a1df4e5ca..ec215c9a664 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -38,6 +38,39 @@ pub fn non_const<T>() -> usize { size_of_t() } +// EMIT_MIR lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff +pub fn transmute_inhabited(c: std::cmp::Ordering) -> i8 { + unsafe { std::mem::transmute(c) } +} + +// EMIT_MIR lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_uninhabited(u: ()) -> Never { + unsafe { std::mem::transmute::<(), Never>(u) } +} + +// EMIT_MIR lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff +pub unsafe fn transmute_ref_dst<T: ?Sized>(u: &T) -> *const T { + unsafe { std::mem::transmute(u) } +} + +// EMIT_MIR lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_ref_uninhabited() -> ! { + let x: &Never = std::mem::transmute(1usize); + match *x {} +} + +// EMIT_MIR lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_mut_uninhabited() -> ! { + let x: &mut Never = std::mem::transmute(1usize); + match *x {} +} + +// EMIT_MIR lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_box_uninhabited() -> ! { + let x: Box<Never> = std::mem::transmute(1usize); + match *x {} +} + pub enum E { A, B, @@ -91,3 +124,12 @@ pub fn read_via_copy_uninhabited(r: &Never) -> Never { } pub enum Never {} + +// EMIT_MIR lower_intrinsics.option_payload.LowerIntrinsics.diff +#[cfg(not(bootstrap))] +pub fn option_payload(o: &Option<usize>, p: &Option<String>) { + unsafe { + let _x = core::intrinsics::option_payload_ptr(o); + let _y = core::intrinsics::option_payload_ptr(p); + } +} diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..814368ec021 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff @@ -0,0 +1,27 @@ +- // MIR for `transmute_inhabited` before LowerIntrinsics ++ // MIR for `transmute_inhabited` after LowerIntrinsics + + fn transmute_inhabited(_1: std::cmp::Ordering) -> i8 { + debug c => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:28: +0:29 + let mut _0: i8; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:56 + let mut _2: std::cmp::Ordering; // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 +- _0 = transmute::<std::cmp::Ordering, i8>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:43:14: 43:33 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(std::cmp::Ordering) -> i8 {transmute::<std::cmp::Ordering, i8>}, val: Value(<ZST>) } ++ _0 = move _2 as i8 (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 + } + + bb1: { + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36 + return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff new file mode 100644 index 00000000000..5440c7a4c8e --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff @@ -0,0 +1,27 @@ +- // MIR for `transmute_ref_dst` before LowerIntrinsics ++ // MIR for `transmute_ref_dst` after LowerIntrinsics + + fn transmute_ref_dst(_1: &T) -> *const T { + debug u => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:44: +0:45 + let mut _0: *const T; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:62 + let mut _2: &T; // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 +- _0 = transmute::<&T, *const T>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:53:14: 53:33 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&T) -> *const T {transmute::<&T, *const T>}, val: Value(<ZST>) } ++ _0 = move _2 as *const T (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 + } + + bb1: { + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36 + return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..43ddccc1ef7 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_box_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_box_uninhabited` after LowerIntrinsics + + fn transmute_to_box_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, Box<Never>>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:70:25: 70:44 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box<Never> {transmute::<usize, Box<Never>>}, val: Value(<ZST>) } ++ _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..bf529a9ca67 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_mut_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_mut_uninhabited` after LowerIntrinsics + + fn transmute_to_mut_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: &mut Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, &mut Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:64:25: 64:44 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::<usize, &mut Never>}, val: Value(<ZST>) } ++ _2 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..4940a99021f --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_ref_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_ref_uninhabited` after LowerIntrinsics + + fn transmute_to_ref_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, &Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:58:21: 58:40 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::<usize, &Never>}, val: Value(<ZST>) } ++ _2 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..f3a12b9ba5f --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,22 @@ +- // MIR for `transmute_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_uninhabited` after LowerIntrinsics + + fn transmute_uninhabited(_1: ()) -> Never { + debug u => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:37: +0:38 + let mut _0: Never; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:47: +0:52 + let mut _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:47: +1:48 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48 +- _0 = transmute::<(), Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:48:14: 48:46 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Never {transmute::<(), Never>}, val: Value(<ZST>) } ++ _0 = move _2 as Never (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 ++ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff index 9870a70dec5..3b9a41249a4 100644 --- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff @@ -32,7 +32,7 @@ _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54 - _3 = add_with_overflow::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:78:14: 78:49 +- // + span: $DIR/lower_intrinsics.rs:111:14: 111:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::<i32>}, val: Value(<ZST>) } + _3 = CheckedAdd(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 @@ -48,7 +48,7 @@ _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54 - _6 = sub_with_overflow::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:79:14: 79:49 +- // + span: $DIR/lower_intrinsics.rs:112:14: 112:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::<i32>}, val: Value(<ZST>) } + _6 = CheckedSub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 + goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 @@ -64,7 +64,7 @@ _11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54 - _9 = mul_with_overflow::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:80:14: 80:49 +- // + span: $DIR/lower_intrinsics.rs:113:14: 113:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::<i32>}, val: Value(<ZST>) } + _9 = CheckedMul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 + goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 diff --git a/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir b/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir index f6d8bdd7422..adfc6b2731c 100644 --- a/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir +++ b/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir @@ -12,7 +12,6 @@ fn f_u64() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21 - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21 _2 = f_non_zst::<u64>(const 0_u64) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21 // mir::Constant // + span: $DIR/lower_intrinsics_e2e.rs:23:9: 23:18 @@ -20,7 +19,6 @@ fn f_u64() -> () { } bb1: { - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:21: 23:22 StorageDead(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21 return; // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2 } diff --git a/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir b/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir index b672e1a6e63..302ca09aac4 100644 --- a/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir +++ b/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir @@ -2,26 +2,21 @@ fn f_unit() -> () { let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics_e2e.rs:+0:17: +0:17 - let mut _1: (); // in scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18 scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics_e2e.rs:9:5: 9:19 - debug t => _1; // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23 - let _2: (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17 + debug t => const (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23 + let _1: (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17 scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics_e2e.rs:20:8: 20:32 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18 - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17 - _2 = f_zst::<()>(move _1) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17 + _1 = f_zst::<()>(const ()) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17 // mir::Constant // + span: $DIR/lower_intrinsics_e2e.rs:21:9: 21:14 // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(<ZST>) } } bb1: { - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:17: 21:18 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:18: +1:19 return; // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff index 07e4dd41813..7713649c5b9 100644 --- a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff +++ b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -11,7 +11,7 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 + nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL @@ -23,7 +23,7 @@ bb2: { StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 + nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:32: +2:2 return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2 } diff --git a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff index e809ca4e900..533db4051ef 100644 --- a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +++ b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -11,7 +11,7 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 + nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL @@ -23,7 +23,7 @@ bb2: { StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 + nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:27: +2:2 return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2 } diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff index 087f76dbda8..04a2d54e9a1 100644 --- a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff +++ b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -11,7 +11,7 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 +- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL @@ -19,7 +19,7 @@ - - bb1: { StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 +- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 - nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:17: +2:2 return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2 } diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff index 933d6895f45..782d0c6c5f2 100644 --- a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +++ b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -11,7 +11,7 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 +- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:5: +1:12 StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:10: +1:11 - drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL @@ -19,7 +19,7 @@ - - bb1: { StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:11: +1:12 - StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 +- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13 - nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:36: +2:2 return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2 } diff --git a/tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir b/tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir index af34bc5edb7..7ac9ef3d490 100644 --- a/tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir +++ b/tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir @@ -2,12 +2,9 @@ fn get_union() -> Foo { let mut _0: Foo; // return place in scope 0 at $DIR/remove_zsts.rs:+0:19: +0:22 - let mut _1: (); // in scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16 bb0: { - StorageLive(_1); // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16 - _0 = Foo { x: move _1 }; // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18 - StorageDead(_1); // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18 + _0 = Foo { x: const () }; // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18 return; // scope 0 at $DIR/remove_zsts.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff b/tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff index 0af29b2babc..edd86ef0aa9 100644 --- a/tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff +++ b/tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff @@ -6,11 +6,14 @@ let mut _1: (); // in scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16 bb0: { - StorageLive(_1); // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16 +- StorageLive(_1); // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16 - _1 = (); // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16 +- _0 = Foo { x: move _1 }; // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18 +- StorageDead(_1); // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18 + nop; // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16 - _0 = Foo { x: move _1 }; // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18 - StorageDead(_1); // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18 ++ nop; // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16 ++ _0 = Foo { x: const () }; // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18 ++ nop; // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18 return; // scope 0 at $DIR/remove_zsts.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index cfcd43093c0..bdf1de468b3 100644 --- a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -12,7 +12,6 @@ let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _16: i32; // in scope 0 at $SRC_DIR/core/src/result.rs:LL:COL scope 1 { debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 scope 2 { @@ -23,7 +22,7 @@ scope 9 { debug e => _14; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL - debug t => _16; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + debug t => _14; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } } } @@ -90,10 +89,7 @@ StorageLive(_14); // scope 2 at $DIR/separate_const_switch.rs:+1:8: +1:10 _14 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL StorageLive(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _16 = move _14; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _15 = move _16; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + _15 = move _14; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL _0 = Result::<i32, i32>::Err(move _15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_14); // scope 2 at $DIR/separate_const_switch.rs:+1:8: +1:10 diff --git a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir index 66ba4df767c..cae89fb177a 100644 --- a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir @@ -3,30 +3,28 @@ fn ezmap(_1: Option<i32>) -> Option<i32> { debug x => _1; // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15 let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44 - let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21 scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]>) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22 debug slf => _1; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20 - debug f => _2; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34 - let mut _3: isize; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16 - let _4: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 - let mut _5: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 + debug f => const ZeroSized: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34 + let mut _2: isize; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16 + let _3: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 + let mut _4: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 scope 2 { - debug x => _4; // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 + debug x => _3; // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - debug n => _4; // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14 + debug n => _3; // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14 } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21 - _3 = discriminant(_1); // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14 - switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14 + _2 = discriminant(_1); // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14 + switchInt(move _2) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14 } bb1: { _0 = Option::<i32>::None; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21 - goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21 + return; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21 } bb2: { @@ -34,16 +32,11 @@ fn ezmap(_1: Option<i32>) -> Option<i32> { } bb3: { - _4 = ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 - StorageLive(_5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - _5 = Add(_4, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 - _0 = Option::<i32>::Some(move _5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 - StorageDead(_5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30 - goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2 - } - - bb4: { - StorageDead(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22 - return; // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2 + _3 = ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 + StorageLive(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 + _4 = Add(_3, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 + _0 = Option::<i32>::Some(move _4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 + StorageDead(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30 + return; // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2 } } diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff index f9e22866bee..ac79e727013 100644 --- a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff +++ b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff @@ -14,7 +14,6 @@ } bb1: { - StorageLive(_2); // scope 0 at $DIR/simplify_if.rs:+2:9: +2:15 _2 = noop() -> bb2; // scope 0 at $DIR/simplify_if.rs:+2:9: +2:15 // mir::Constant // + span: $DIR/simplify_if.rs:7:9: 7:13 @@ -22,7 +21,6 @@ } bb2: { - StorageDead(_2); // scope 0 at $DIR/simplify_if.rs:+2:15: +2:16 goto -> bb4; // scope 0 at $DIR/simplify_if.rs:+1:5: +3:6 } diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir index 391b00effac..3884d29db41 100644 --- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir @@ -4,21 +4,13 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _4: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _5: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _6: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _7: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 bb0: { - goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb8; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb1: { @@ -30,72 +22,34 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () { } bb3 (cleanup): { - _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _4 = &raw mut (*_1)[_3]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _3 = Add(move _3, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + drop((*_4)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb4 (cleanup): { - _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _6) -> [0: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _5 = Eq(_3, _2); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + switchInt(move _5) -> [0: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb5: { - _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _6 = &raw mut (*_1)[_3]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _3 = Add(move _3, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + drop((*_6)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb6: { - _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _8) -> [0: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _7 = Eq(_3, _2); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + switchInt(move _7) -> [0: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb7: { - _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _2 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _3 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb8: { goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } - - bb9 (cleanup): { - _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb10 (cleanup): { - _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _12) -> [0: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb11: { - _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb12: { - _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _14) -> [0: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb13: { - _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = move _15 as *mut std::string::String (PtrToPtr); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb14: { - goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb15: { - _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _2) -> [0: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } } diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index e0fa1fe2824..4020a433d62 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -32,13 +32,11 @@ fn bar() ({ ({ let res = ((::alloc::fmt::format as - for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1 + for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_const as - fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test" - as &str)] as [&str; 1]) as &[&str; 1]), - (&([] as [core::fmt::ArgumentV1<'_>; 0]) as - &[core::fmt::ArgumentV1<'_>; 0])) as Arguments<'_>)) as - String); + fn(&[&'static str]) -> Arguments<'_> {Arguments::<'_>::new_const})((&([("test" + as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>)) + as String); (res as String) } as String); } as ()) diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp index 15dcd4ed97d..58f746f2e0e 100644 --- a/tests/pretty/tests-are-sorted.pp +++ b/tests/pretty/tests-are-sorted.pp @@ -4,7 +4,7 @@ use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; -// compile-flags: --crate-type=lib --test +// compile-flags: --crate-type=lib --test --remap-path-prefix={{src-base}}/=/the/src/ --remap-path-prefix={{src-base}}\=/the/src/ // pretty-compare-only // pretty-mode:expanded // pp-exact:tests-are-sorted.pp @@ -18,6 +18,11 @@ pub const m_test: test::TestDescAndFn = name: test::StaticTestName("m_test"), ignore: false, ignore_message: ::core::option::Option::None, + source_file: "/the/src/tests-are-sorted.rs", + start_line: 7usize, + start_col: 4usize, + end_line: 7usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, @@ -34,8 +39,13 @@ pub const z_test: test::TestDescAndFn = test::TestDescAndFn { desc: test::TestDesc { name: test::StaticTestName("z_test"), - ignore: false, - ignore_message: ::core::option::Option::None, + ignore: true, + ignore_message: ::core::option::Option::Some("not yet implemented"), + source_file: "/the/src/tests-are-sorted.rs", + start_line: 11usize, + start_col: 4usize, + end_line: 11usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, @@ -43,6 +53,7 @@ pub const z_test: test::TestDescAndFn = }, testfn: test::StaticTestFn(|| test::assert_test_result(z_test())), }; +#[ignore = "not yet implemented"] fn z_test() {} extern crate test; @@ -54,6 +65,11 @@ pub const a_test: test::TestDescAndFn = name: test::StaticTestName("a_test"), ignore: false, ignore_message: ::core::option::Option::None, + source_file: "/the/src/tests-are-sorted.rs", + start_line: 14usize, + start_col: 4usize, + end_line: 14usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, diff --git a/tests/pretty/tests-are-sorted.rs b/tests/pretty/tests-are-sorted.rs index 1f737d54719..39e0922250b 100644 --- a/tests/pretty/tests-are-sorted.rs +++ b/tests/pretty/tests-are-sorted.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-type=lib --test +// compile-flags: --crate-type=lib --test --remap-path-prefix={{src-base}}/=/the/src/ --remap-path-prefix={{src-base}}\=/the/src/ // pretty-compare-only // pretty-mode:expanded // pp-exact:tests-are-sorted.pp @@ -7,6 +7,7 @@ fn m_test() {} #[test] +#[ignore = "not yet implemented"] fn z_test() {} #[test] diff --git a/tests/run-make-fulldeps/issue-83045/Makefile b/tests/run-make-fulldeps/issue-83045/Makefile index 34853cb1d31..fc180ccfe28 100644 --- a/tests/run-make-fulldeps/issue-83045/Makefile +++ b/tests/run-make-fulldeps/issue-83045/Makefile @@ -29,5 +29,5 @@ all: --crate-type=rlib \ --edition=2018 \ c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0 - $(CGREP) E0463 < $(TMPDIR)/output.txt + $(CGREP) E0519 < $(TMPDIR)/output.txt $(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt diff --git a/tests/run-make-fulldeps/tools.mk b/tests/run-make-fulldeps/tools.mk index 0f5425daa16..ea06b620c4c 100644 --- a/tests/run-make-fulldeps/tools.mk +++ b/tests/run-make-fulldeps/tools.mk @@ -112,9 +112,9 @@ endif # Extra flags needed to compile a working executable with the standard library ifdef IS_WINDOWS ifdef IS_MSVC - EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib + EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib else - EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt + EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll EXTRACXXFLAGS := -lstdc++ # So this is a bit hacky: we can't use the DLL version of libstdc++ because # it pulls in the DLL version of libgcc, which means that we end up with 2 diff --git a/tests/run-make/issue-36710/Makefile b/tests/run-make/issue-36710/Makefile index d6145c07126..c6b71f5fbd4 100644 --- a/tests/run-make/issue-36710/Makefile +++ b/tests/run-make/issue-36710/Makefile @@ -4,6 +4,7 @@ # ignore-nvptx64-nvidia-cuda FIXME: can't find crate for `std` # ignore-musl FIXME: this makefile needs teaching how to use a musl toolchain # (see dist-i586-gnu-i586-i686-musl Dockerfile) +# ignore-sgx include ../../run-make-fulldeps/tools.mk diff --git a/tests/run-make/raw-dylib-cross-compilation/Makefile b/tests/run-make/raw-dylib-cross-compilation/Makefile new file mode 100644 index 00000000000..2a714f3a11f --- /dev/null +++ b/tests/run-make/raw-dylib-cross-compilation/Makefile @@ -0,0 +1,22 @@ +# Tests that raw-dylib cross compilation works correctly + +# only-gnu +# needs-i686-dlltool +# needs-x86_64-dlltool + +# i686 dlltool.exe can't product x64 binaries. +# ignore-i686-pc-windows-gnu + +include ../../run-make-fulldeps/tools.mk + +all: + # Build as x86 and make sure that we have x86 objects only. + $(RUSTC) --crate-type lib --crate-name i686_raw_dylib_test --target i686-pc-windows-gnu lib.rs + "$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libi686_raw_dylib_test.rlib > $(TMPDIR)/i686.objdump.txt + $(CGREP) "file format coff-i386" < $(TMPDIR)/i686.objdump.txt + $(CGREP) -v "file format coff-x86-64" < $(TMPDIR)/i686.objdump.txt + # Build as x64 and make sure that we have x64 objects only. + $(RUSTC) --crate-type lib --crate-name x64_raw_dylib_test --target x86_64-pc-windows-gnu lib.rs + "$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libx64_raw_dylib_test.rlib > $(TMPDIR)/x64.objdump.txt + $(CGREP) "file format coff-x86-64" < $(TMPDIR)/x64.objdump.txt + $(CGREP) -v "file format coff-i386" < $(TMPDIR)/x64.objdump.txt diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs new file mode 100644 index 00000000000..51bf2ec6b6e --- /dev/null +++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs @@ -0,0 +1,20 @@ +#![feature(raw_dylib)] +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +// This is needed because of #![no_core]: +#[lang = "sized"] +trait Sized {} + +#[link(name = "extern_1", kind = "raw-dylib")] +extern { + fn extern_fn(); +} + +pub fn extern_fn_caller() { + unsafe { + extern_fn(); + } +} diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks index e839c200bbb..af9bc8c1d62 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks @@ -1,8 +1,7 @@ CHECK: cc_plus_one_asm CHECK-NEXT: movl CHECK-NEXT: lfence -CHECK-NEXT: inc -CHECK-NEXT: notq (%rsp) -CHECK-NEXT: notq (%rsp) +CHECK-NEXT: incl +CHECK-NEXT: shlq $0, (%rsp) CHECK-NEXT: lfence CHECK-NEXT: retq diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks index 15211e3ade7..885bf461bf3 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks @@ -1,8 +1,24 @@ -CHECK: libunwind::Registers_x86_64::jumpto +CHECK: __libunwind_Registers_x86_64_jumpto CHECK: lfence CHECK: lfence CHECK: lfence CHECK: lfence -CHECK: shlq $0, (%rsp) +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] CHECK-NEXT: lfence -CHECK-NEXT: retq +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks index 0fe88141b24..8a5493650a7 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks @@ -2,6 +2,5 @@ CHECK: print CHECK: lfence CHECK: lfence CHECK: lfence -CHECK: popq CHECK: callq 0x{{[[:xdigit:]]*}} <_Unwind_Resume> CHECK-NEXT: ud2 diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index 944343df6e5..235bb603b84 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -20,39 +20,38 @@ function build { } function check { - local func=$1 + local func_re="$1" local checks="${TEST_DIR}/$2" local asm=$(mktemp) - local objdump="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump" - local filecheck="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck" - - ${objdump} --disassemble-symbols=${func} --demangle \ - ${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave > ${asm} + local objdump="${LLVM_BIN_DIR}/llvm-objdump" + local filecheck="${LLVM_BIN_DIR}/FileCheck" + local enclave=${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave + + func="$(${objdump} --syms --demangle ${enclave} | \ + grep --only-matching -E "[[:blank:]]+${func_re}\$" | \ + sed -e 's/^[[:space:]]*//' )" + ${objdump} --disassemble-symbols="${func}" --demangle \ + ${enclave} > ${asm} ${filecheck} --input-file ${asm} ${checks} } build -check unw_getcontext unw_getcontext.checks -check "libunwind::Registers_x86_64::jumpto()" jumpto.checks -check "std::io::stdio::_print::h87f0c238421c45bc" print.checks -check rust_plus_one_global_asm rust_plus_one_global_asm.checks \ - || echo "warning: module level assembly currently not hardened" +check "unw_getcontext" unw_getcontext.checks +check "__libunwind_Registers_x86_64_jumpto" jumpto.checks +check 'std::io::stdio::_print::[[:alnum:]]+' print.checks +check rust_plus_one_global_asm rust_plus_one_global_asm.checks check cc_plus_one_c cc_plus_one_c.checks check cc_plus_one_c_asm cc_plus_one_c_asm.checks check cc_plus_one_cxx cc_plus_one_cxx.checks check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks -check cc_plus_one_asm cc_plus_one_asm.checks \ - || echo "warning: the cc crate forwards assembly files to the CC compiler." \ - "Clang uses its own integrated assembler, which does not include the LVI passes." +check cc_plus_one_asm cc_plus_one_asm.checks check cmake_plus_one_c cmake_plus_one_c.checks check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks -check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks \ - || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks check cmake_plus_one_cxx cmake_plus_one_cxx.checks check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks -check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks \ - || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks check cmake_plus_one_asm cmake_plus_one_asm.checks diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml new file mode 100644 index 00000000000..0ebb96d7870 --- /dev/null +++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml @@ -0,0 +1,51 @@ +// This test ensures that the "Auto-hide item contents for large items" setting is working as +// expected. + +// We need to disable this check because `implementors/test_docs/trait.Iterator.js` doesn't exist. +fail-on-request-error: false + +define-function: ( + "check-setting", + (storage_value, setting_attribute_value, toggle_attribute_value), + block { + assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|} + click: "#settings-menu" + wait-for: "#settings" + assert-property: ("#auto-hide-large-items", {"checked": |setting_attribute_value|}) + assert-attribute: (".item-decl .type-contents-toggle", {"open": |toggle_attribute_value|}) + } +) + +goto: "file://" + |DOC_PATH| + "/lib2/scroll_traits/trait.Iterator.html" + +// We check that the setting is enabled by default and is working. +call-function: ("check-setting", { + "storage_value": null, + "setting_attribute_value": "true", + "toggle_attribute_value": null, +}) + +// Now we change its value. +click: "#auto-hide-large-items" +assert-local-storage: {"rustdoc-auto-hide-large-items": "false"} + +// We check that the changes were applied as expected. +reload: + +call-function: ("check-setting", { + "storage_value": "false", + "setting_attribute_value": "false", + "toggle_attribute_value": "", +}) + +// And now we re-enable the setting. +click: "#auto-hide-large-items" +assert-local-storage: {"rustdoc-auto-hide-large-items": "true"} + +// And we check everything is back the way it was before. +reload: +call-function: ("check-setting", { + "storage_value": "true", + "setting_attribute_value": "true", + "toggle_attribute_value": null, +}) diff --git a/tests/rustdoc-js-std/option-type-signatures.js b/tests/rustdoc-js-std/option-type-signatures.js index dee4819e81a..6bf421a2135 100644 --- a/tests/rustdoc-js-std/option-type-signatures.js +++ b/tests/rustdoc-js-std/option-type-signatures.js @@ -1,7 +1,18 @@ -const QUERY = 'option, fnonce -> option'; +const QUERY = [ + 'option, fnonce -> option', + 'option -> default', +]; -const EXPECTED = { - 'others': [ - { 'path': 'std::option::Option', 'name': 'map' }, - ], -}; +const EXPECTED = [ + { + 'others': [ + { 'path': 'std::option::Option', 'name': 'map' }, + ], + }, + { + 'others': [ + { 'path': 'std::option::Option', 'name': 'unwrap_or_default' }, + { 'path': 'std::option::Option', 'name': 'get_or_insert_default' }, + ], + }, +]; diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index 98c6f27ca61..d1aa840ab08 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -17,6 +17,7 @@ const QUERY = [ "a b:", "a (b:", "_:", + "_:a", "a-bb", "a>bb", "ab'", @@ -48,7 +49,6 @@ const PARSED = [ foundElems: 0, original: "<P>", returned: [], - typeFilter: -1, userQuery: "<p>", error: "Found generics without a path", }, @@ -57,7 +57,6 @@ const PARSED = [ foundElems: 0, original: "-> <P>", returned: [], - typeFilter: -1, userQuery: "-> <p>", error: "Found generics without a path", }, @@ -66,7 +65,6 @@ const PARSED = [ foundElems: 0, original: "a<\"P\">", returned: [], - typeFilter: -1, userQuery: "a<\"p\">", error: "Unexpected `\"` in generics", }, @@ -75,7 +73,6 @@ const PARSED = [ foundElems: 0, original: "\"P\" \"P\"", returned: [], - typeFilter: -1, userQuery: "\"p\" \"p\"", error: "Cannot have more than one literal search element", }, @@ -84,7 +81,6 @@ const PARSED = [ foundElems: 0, original: "P \"P\"", returned: [], - typeFilter: -1, userQuery: "p \"p\"", error: "Cannot use literal search when there is more than one element", }, @@ -93,7 +89,6 @@ const PARSED = [ foundElems: 0, original: "\"p\" p", returned: [], - typeFilter: -1, userQuery: "\"p\" p", error: "You cannot have more than one element if you use quotes", }, @@ -102,7 +97,6 @@ const PARSED = [ foundElems: 0, original: "\"const\": p", returned: [], - typeFilter: -1, userQuery: "\"const\": p", error: "You cannot use quotes on type filter", }, @@ -111,16 +105,14 @@ const PARSED = [ foundElems: 0, original: "a<:a>", returned: [], - typeFilter: -1, userQuery: "a<:a>", - error: "Unexpected `:` after `<`", + error: "Expected type filter before `:`", }, { elems: [], foundElems: 0, original: "a<::a>", returned: [], - typeFilter: -1, userQuery: "a<::a>", error: "Unexpected `::`: paths cannot start with `::`", }, @@ -129,7 +121,6 @@ const PARSED = [ foundElems: 0, original: "((a))", returned: [], - typeFilter: -1, userQuery: "((a))", error: "Unexpected `(`", }, @@ -138,7 +129,6 @@ const PARSED = [ foundElems: 0, original: "(p -> p", returned: [], - typeFilter: -1, userQuery: "(p -> p", error: "Unexpected `(`", }, @@ -147,7 +137,6 @@ const PARSED = [ foundElems: 0, original: "::a::b", returned: [], - typeFilter: -1, userQuery: "::a::b", error: "Paths cannot start with `::`", }, @@ -156,7 +145,6 @@ const PARSED = [ foundElems: 0, original: "a::::b", returned: [], - typeFilter: -1, userQuery: "a::::b", error: "Unexpected `::::`", }, @@ -165,7 +153,6 @@ const PARSED = [ foundElems: 0, original: "a::b::", returned: [], - typeFilter: -1, userQuery: "a::b::", error: "Paths cannot end with `::`", }, @@ -174,7 +161,6 @@ const PARSED = [ foundElems: 0, original: ":a", returned: [], - typeFilter: -1, userQuery: ":a", error: "Expected type filter before `:`", }, @@ -183,16 +169,14 @@ const PARSED = [ foundElems: 0, original: "a b:", returned: [], - typeFilter: -1, userQuery: "a b:", - error: "Unexpected `:`", + error: "Unexpected `:` (expected path after type filter)", }, { elems: [], foundElems: 0, original: "a (b:", returned: [], - typeFilter: -1, userQuery: "a (b:", error: "Unexpected `(`", }, @@ -201,8 +185,15 @@ const PARSED = [ foundElems: 0, original: "_:", returned: [], - typeFilter: -1, userQuery: "_:", + error: "Unexpected `:` (expected path after type filter)", + }, + { + elems: [], + foundElems: 0, + original: "_:a", + returned: [], + userQuery: "_:a", error: "Unknown type filter `_`", }, { @@ -210,7 +201,6 @@ const PARSED = [ foundElems: 0, original: "a-bb", returned: [], - typeFilter: -1, userQuery: "a-bb", error: "Unexpected `-` (did you mean `->`?)", }, @@ -219,7 +209,6 @@ const PARSED = [ foundElems: 0, original: "a>bb", returned: [], - typeFilter: -1, userQuery: "a>bb", error: "Unexpected `>` (did you mean `->`?)", }, @@ -228,7 +217,6 @@ const PARSED = [ foundElems: 0, original: "ab'", returned: [], - typeFilter: -1, userQuery: "ab'", error: "Unexpected `'`", }, @@ -237,7 +225,6 @@ const PARSED = [ foundElems: 0, original: "a->", returned: [], - typeFilter: -1, userQuery: "a->", error: "Expected at least one item after `->`", }, @@ -246,7 +233,6 @@ const PARSED = [ foundElems: 0, original: '"p" <a>', returned: [], - typeFilter: -1, userQuery: '"p" <a>', error: "Found generics without a path", }, @@ -255,7 +241,6 @@ const PARSED = [ foundElems: 0, original: '"p" a<a>', returned: [], - typeFilter: -1, userQuery: '"p" a<a>', error: "You cannot have more than one element if you use quotes", }, @@ -264,7 +249,6 @@ const PARSED = [ foundElems: 0, original: 'a,<', returned: [], - typeFilter: -1, userQuery: 'a,<', error: 'Found generics without a path', }, @@ -273,7 +257,6 @@ const PARSED = [ foundElems: 0, original: 'aaaaa<>b', returned: [], - typeFilter: -1, userQuery: 'aaaaa<>b', error: 'Expected `,`, ` `, `:` or `->`, found `b`', }, @@ -282,16 +265,14 @@ const PARSED = [ foundElems: 0, original: 'fn:aaaaa<>b', returned: [], - typeFilter: -1, userQuery: 'fn:aaaaa<>b', - error: 'Expected `,`, ` ` or `->`, found `b`', + error: 'Expected `,`, ` `, `:` or `->`, found `b`', }, { elems: [], foundElems: 0, original: '->a<>b', returned: [], - typeFilter: -1, userQuery: '->a<>b', error: 'Expected `,` or ` `, found `b`', }, @@ -300,7 +281,6 @@ const PARSED = [ foundElems: 0, original: 'a<->', returned: [], - typeFilter: -1, userQuery: 'a<->', error: 'Unexpected `-` after `<`', }, @@ -309,7 +289,6 @@ const PARSED = [ foundElems: 0, original: 'a:: a', returned: [], - typeFilter: -1, userQuery: 'a:: a', error: 'Paths cannot end with `::`', }, @@ -318,7 +297,6 @@ const PARSED = [ foundElems: 0, original: 'a ::a', returned: [], - typeFilter: -1, userQuery: 'a ::a', error: 'Paths cannot start with `::`', }, @@ -327,16 +305,14 @@ const PARSED = [ foundElems: 0, original: "a<a>:", returned: [], - typeFilter: -1, userQuery: "a<a>:", - error: 'Unexpected `:`', + error: 'Unexpected `<` in type filter', }, { elems: [], foundElems: 0, original: "a<>:", returned: [], - typeFilter: -1, userQuery: "a<>:", error: 'Unexpected `<` in type filter', }, @@ -345,7 +321,6 @@ const PARSED = [ foundElems: 0, original: "a,:", returned: [], - typeFilter: -1, userQuery: "a,:", error: 'Unexpected `,` in type filter', }, @@ -354,7 +329,6 @@ const PARSED = [ foundElems: 0, original: "a<> :", returned: [], - typeFilter: -1, userQuery: "a<> :", error: 'Unexpected `<` in type filter', }, @@ -363,7 +337,6 @@ const PARSED = [ foundElems: 0, original: "mod : :", returned: [], - typeFilter: -1, userQuery: "mod : :", error: 'Unexpected `:`', }, @@ -372,7 +345,6 @@ const PARSED = [ foundElems: 0, original: "a!a", returned: [], - typeFilter: -1, userQuery: "a!a", error: 'Unexpected `!`: it can only be at the end of an ident', }, @@ -381,7 +353,6 @@ const PARSED = [ foundElems: 0, original: "a!!", returned: [], - typeFilter: -1, userQuery: "a!!", error: 'Cannot have more than one `!` in an ident', }, @@ -390,7 +361,6 @@ const PARSED = [ foundElems: 0, original: "mod:a!", returned: [], - typeFilter: -1, userQuery: "mod:a!", error: 'Invalid search type: macro `!` and `mod` both specified', }, @@ -399,7 +369,6 @@ const PARSED = [ foundElems: 0, original: "a!::a", returned: [], - typeFilter: -1, userQuery: "a!::a", error: 'Cannot have associated items in macros', }, @@ -408,7 +377,6 @@ const PARSED = [ foundElems: 0, original: "a<", returned: [], - typeFilter: -1, userQuery: "a<", error: "Unclosed `<`", }, diff --git a/tests/rustdoc-js-std/parser-filter.js b/tests/rustdoc-js-std/parser-filter.js index 01f65b478f8..e23447ab75d 100644 --- a/tests/rustdoc-js-std/parser-filter.js +++ b/tests/rustdoc-js-std/parser-filter.js @@ -1,4 +1,14 @@ -const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo', 'macro!', 'macro:mac!', 'a::mac!']; +const QUERY = [ + 'fn:foo', + 'enum : foo', + 'macro<f>:foo', + 'macro!', + 'macro:mac!', + 'a::mac!', + '-> fn:foo', + '-> fn:foo<fn:bar>', + '-> fn:foo<fn:bar, enum : baz::fuzz>', +]; const PARSED = [ { @@ -8,11 +18,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "foo", generics: [], + typeFilter: 5, }], foundElems: 1, original: "fn:foo", returned: [], - typeFilter: 5, userQuery: "fn:foo", error: null, }, @@ -23,11 +33,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "foo", generics: [], + typeFilter: 4, }], foundElems: 1, original: "enum : foo", returned: [], - typeFilter: 4, userQuery: "enum : foo", error: null, }, @@ -36,9 +46,8 @@ const PARSED = [ foundElems: 0, original: "macro<f>:foo", returned: [], - typeFilter: -1, userQuery: "macro<f>:foo", - error: "Unexpected `:`", + error: "Unexpected `<` in type filter", }, { elems: [{ @@ -47,11 +56,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "macro", generics: [], + typeFilter: 14, }], foundElems: 1, original: "macro!", returned: [], - typeFilter: 14, userQuery: "macro!", error: null, }, @@ -62,11 +71,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "mac", generics: [], + typeFilter: 14, }], foundElems: 1, original: "macro:mac!", returned: [], - typeFilter: 14, userQuery: "macro:mac!", error: null, }, @@ -77,12 +86,83 @@ const PARSED = [ pathWithoutLast: ["a"], pathLast: "mac", generics: [], + typeFilter: 14, }], foundElems: 1, original: "a::mac!", returned: [], - typeFilter: 14, userQuery: "a::mac!", error: null, }, + { + elems: [], + foundElems: 1, + original: "-> fn:foo", + returned: [{ + name: "foo", + fullPath: ["foo"], + pathWithoutLast: [], + pathLast: "foo", + generics: [], + typeFilter: 5, + }], + userQuery: "-> fn:foo", + error: null, + }, + { + elems: [], + foundElems: 1, + original: "-> fn:foo<fn:bar>", + returned: [{ + name: "foo", + fullPath: ["foo"], + pathWithoutLast: [], + pathLast: "foo", + generics: [ + { + name: "bar", + fullPath: ["bar"], + pathWithoutLast: [], + pathLast: "bar", + generics: [], + typeFilter: 5, + } + ], + typeFilter: 5, + }], + userQuery: "-> fn:foo<fn:bar>", + error: null, + }, + { + elems: [], + foundElems: 1, + original: "-> fn:foo<fn:bar, enum : baz::fuzz>", + returned: [{ + name: "foo", + fullPath: ["foo"], + pathWithoutLast: [], + pathLast: "foo", + generics: [ + { + name: "bar", + fullPath: ["bar"], + pathWithoutLast: [], + pathLast: "bar", + generics: [], + typeFilter: 5, + }, + { + name: "baz::fuzz", + fullPath: ["baz", "fuzz"], + pathWithoutLast: ["baz"], + pathLast: "fuzz", + generics: [], + typeFilter: 4, + }, + ], + typeFilter: 5, + }], + userQuery: "-> fn:foo<fn:bar, enum : baz::fuzz>", + error: null, + }, ]; diff --git a/tests/rustdoc-js-std/parser-generics.js b/tests/rustdoc-js-std/parser-generics.js index 0cf7f5019aa..c448d845acb 100644 --- a/tests/rustdoc-js-std/parser-generics.js +++ b/tests/rustdoc-js-std/parser-generics.js @@ -6,7 +6,6 @@ const PARSED = [ foundElems: 0, original: 'A<B<C<D>, E>', returned: [], - typeFilter: -1, userQuery: 'a<b<c<d>, e>', error: 'Unexpected `<` after `<`', }, @@ -18,6 +17,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "p", generics: [], + typeFilter: -1, }, { name: "u8", @@ -25,12 +25,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "u8", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "p<> u8", returned: [], - typeFilter: -1, userQuery: "p<> u8", error: null, }, @@ -50,12 +50,12 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, ], foundElems: 1, original: '"p"<a>', returned: [], - typeFilter: -1, userQuery: '"p"<a>', error: null, }, diff --git a/tests/rustdoc-js-std/parser-ident.js b/tests/rustdoc-js-std/parser-ident.js index 6c17d00f16e..be42b7aa463 100644 --- a/tests/rustdoc-js-std/parser-ident.js +++ b/tests/rustdoc-js-std/parser-ident.js @@ -23,11 +23,11 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }], foundElems: 1, original: "R<!>", returned: [], - typeFilter: -1, userQuery: "r<!>", error: null, }, @@ -38,11 +38,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "!", generics: [], + typeFilter: -1, }], foundElems: 1, original: "!", returned: [], - typeFilter: -1, userQuery: "!", error: null, }, @@ -53,11 +53,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: 14, }], foundElems: 1, original: "a!", returned: [], - typeFilter: 14, userQuery: "a!", error: null, }, @@ -66,7 +66,6 @@ const PARSED = [ foundElems: 0, original: "a!::b", returned: [], - typeFilter: -1, userQuery: "a!::b", error: "Cannot have associated items in macros", }, @@ -77,11 +76,11 @@ const PARSED = [ pathWithoutLast: ["!"], pathLast: "b", generics: [], + typeFilter: -1, }], foundElems: 1, original: "!::b", returned: [], - typeFilter: -1, userQuery: "!::b", error: null, }, @@ -90,7 +89,6 @@ const PARSED = [ foundElems: 0, original: "a!::b!", returned: [], - typeFilter: -1, userQuery: "a!::b!", error: "Cannot have associated items in macros", }, diff --git a/tests/rustdoc-js-std/parser-literal.js b/tests/rustdoc-js-std/parser-literal.js index 87b3baff1e2..3a31d1bddff 100644 --- a/tests/rustdoc-js-std/parser-literal.js +++ b/tests/rustdoc-js-std/parser-literal.js @@ -16,11 +16,11 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }], foundElems: 1, original: "R<P>", returned: [], - typeFilter: -1, userQuery: "r<p>", error: null, } diff --git a/tests/rustdoc-js-std/parser-paths.js b/tests/rustdoc-js-std/parser-paths.js index 9f823f9336a..f3e421f5ffa 100644 --- a/tests/rustdoc-js-std/parser-paths.js +++ b/tests/rustdoc-js-std/parser-paths.js @@ -8,11 +8,11 @@ const PARSED = [ pathWithoutLast: ["a"], pathLast: "b", generics: [], + typeFilter: -1, }], foundElems: 1, original: "A::B", returned: [], - typeFilter: -1, userQuery: "a::b", error: null, }, @@ -24,6 +24,7 @@ const PARSED = [ pathWithoutLast: ["a"], pathLast: "b", generics: [], + typeFilter: -1, }, { name: "c", @@ -31,12 +32,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "c", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: 'A::B,C', returned: [], - typeFilter: -1, userQuery: 'a::b,c', error: null, }, @@ -56,6 +57,7 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, { name: "c", @@ -63,12 +65,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "c", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: 'A::B<f>,C', returned: [], - typeFilter: -1, userQuery: 'a::b<f>,c', error: null, }, @@ -79,11 +81,11 @@ const PARSED = [ pathWithoutLast: ["mod"], pathLast: "a", generics: [], + typeFilter: -1, }], foundElems: 1, original: "mod::a", returned: [], - typeFilter: -1, userQuery: "mod::a", error: null, }, diff --git a/tests/rustdoc-js-std/parser-quote.js b/tests/rustdoc-js-std/parser-quote.js index 1e16c90de5e..d5d67cac892 100644 --- a/tests/rustdoc-js-std/parser-quote.js +++ b/tests/rustdoc-js-std/parser-quote.js @@ -19,8 +19,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "p", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: '-> "p"', error: null, }, @@ -31,11 +31,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "p", generics: [], + typeFilter: -1, }], foundElems: 1, original: '"p",', returned: [], - typeFilter: -1, userQuery: '"p",', error: null, }, @@ -44,7 +44,6 @@ const PARSED = [ foundElems: 0, original: '"p" -> a', returned: [], - typeFilter: -1, userQuery: '"p" -> a', error: "You cannot have more than one element if you use quotes", }, @@ -53,7 +52,6 @@ const PARSED = [ foundElems: 0, original: '"a" -> "p"', returned: [], - typeFilter: -1, userQuery: '"a" -> "p"', error: "Cannot have more than one literal search element", }, @@ -62,7 +60,6 @@ const PARSED = [ foundElems: 0, original: '->"-"', returned: [], - typeFilter: -1, userQuery: '->"-"', error: 'Unexpected `-` in a string element', }, @@ -71,7 +68,6 @@ const PARSED = [ foundElems: 0, original: '"a', returned: [], - typeFilter: -1, userQuery: '"a', error: 'Unclosed `"`', }, @@ -80,7 +76,6 @@ const PARSED = [ foundElems: 0, original: '""', returned: [], - typeFilter: -1, userQuery: '""', error: 'Cannot have empty string element', }, diff --git a/tests/rustdoc-js-std/parser-returned.js b/tests/rustdoc-js-std/parser-returned.js index 6fce17dcabd..c2981319055 100644 --- a/tests/rustdoc-js-std/parser-returned.js +++ b/tests/rustdoc-js-std/parser-returned.js @@ -25,8 +25,8 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }], - typeFilter: -1, userQuery: "-> f<p>", error: null, }, @@ -40,8 +40,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "p", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: "-> p", error: null, }, @@ -55,8 +55,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: "->,a", error: null, }, @@ -67,6 +67,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "aaaaa", generics: [], + typeFilter: -1, }], foundElems: 2, original: "aaaaa->a", @@ -76,8 +77,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: "aaaaa->a", error: null, }, @@ -91,8 +92,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "!", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: "-> !", error: null, }, diff --git a/tests/rustdoc-js-std/parser-separators.js b/tests/rustdoc-js-std/parser-separators.js index 5b7abdfa8d6..fc8c5114c4e 100644 --- a/tests/rustdoc-js-std/parser-separators.js +++ b/tests/rustdoc-js-std/parser-separators.js @@ -19,6 +19,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'aaaaaa', generics: [], + typeFilter: -1, }, { name: 'b', @@ -26,12 +27,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'b', generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "aaaaaa b", returned: [], - typeFilter: -1, userQuery: "aaaaaa b", error: null, }, @@ -43,6 +44,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'a', generics: [], + typeFilter: -1, }, { name: 'b', @@ -50,12 +52,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'b', generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a b", returned: [], - typeFilter: -1, userQuery: "a b", error: null, }, @@ -67,6 +69,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'a', generics: [], + typeFilter: -1, }, { name: 'b', @@ -74,12 +77,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'b', generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a,b", returned: [], - typeFilter: -1, userQuery: "a,b", error: null, }, @@ -91,6 +94,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'a', generics: [], + typeFilter: -1, }, { name: 'b', @@ -98,12 +102,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'b', generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a\tb", returned: [], - typeFilter: -1, userQuery: "a\tb", error: null, }, @@ -130,12 +134,12 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, ], foundElems: 1, original: "a<b c>", returned: [], - typeFilter: -1, userQuery: "a<b c>", error: null, }, @@ -162,12 +166,12 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, ], foundElems: 1, original: "a<b,c>", returned: [], - typeFilter: -1, userQuery: "a<b,c>", error: null, }, @@ -194,12 +198,12 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, ], foundElems: 1, original: "a<b\tc>", returned: [], - typeFilter: -1, userQuery: "a<b\tc>", error: null, }, diff --git a/tests/rustdoc-js-std/parser-weird-queries.js b/tests/rustdoc-js-std/parser-weird-queries.js index a3d85aeca5e..dc1049a70bc 100644 --- a/tests/rustdoc-js-std/parser-weird-queries.js +++ b/tests/rustdoc-js-std/parser-weird-queries.js @@ -20,6 +20,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }, { name: "b", @@ -27,12 +28,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "b", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a b", returned: [], - typeFilter: -1, userQuery: "a b", error: null, }, @@ -44,6 +45,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }, { name: "b", @@ -51,12 +53,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "b", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a b", returned: [], - typeFilter: -1, userQuery: "a b", error: null, }, @@ -65,7 +67,6 @@ const PARSED = [ foundElems: 0, original: "a,b(c)", returned: [], - typeFilter: -1, userQuery: "a,b(c)", error: "Unexpected `(`", }, @@ -77,6 +78,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "aaa", generics: [], + typeFilter: -1, }, { name: "a", @@ -84,12 +86,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "aaa,a", returned: [], - typeFilter: -1, userQuery: "aaa,a", error: null, }, @@ -98,7 +100,6 @@ const PARSED = [ foundElems: 0, original: ",,,,", returned: [], - typeFilter: -1, userQuery: ",,,,", error: null, }, @@ -107,17 +108,15 @@ const PARSED = [ foundElems: 0, original: 'mod :', returned: [], - typeFilter: 0, userQuery: 'mod :', - error: null, + error: "Unexpected `:` (expected path after type filter)", }, { elems: [], foundElems: 0, original: 'mod\t:', returned: [], - typeFilter: 0, userQuery: 'mod\t:', - error: null, + error: "Unexpected `:` (expected path after type filter)", }, ]; diff --git a/tests/rustdoc-js/generics-impl.js b/tests/rustdoc-js/generics-impl.js index bb6e0041db5..5051743bda2 100644 --- a/tests/rustdoc-js/generics-impl.js +++ b/tests/rustdoc-js/generics-impl.js @@ -5,6 +5,8 @@ const QUERY = [ 'Aaaaaaa -> bool', 'Aaaaaaa -> usize', 'Read -> u64', + 'trait:Read -> u64', + 'struct:Read -> u64', 'bool -> u64', 'Ddddddd -> u64', '-> Ddddddd' @@ -37,6 +39,17 @@ const EXPECTED = [ ], }, { + // trait:Read -> u64 + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' }, + { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' }, + ], + }, + { + // struct:Read -> u64 + 'others': [], + }, + { // bool -> u64 'others': [ { 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' }, diff --git a/tests/rustdoc-js/generics.js b/tests/rustdoc-js/generics.js index 5e5ba7cd9ac..f79c709ad6c 100644 --- a/tests/rustdoc-js/generics.js +++ b/tests/rustdoc-js/generics.js @@ -2,6 +2,8 @@ const QUERY = [ 'R<P>', + 'R<struct:P>', + 'R<enum:P>', '"P"', 'P', 'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>', @@ -21,6 +23,20 @@ const EXPECTED = [ ], }, { + // R<struct:P> + 'returned': [ + { 'path': 'generics', 'name': 'alef' }, + ], + 'in_args': [ + { 'path': 'generics', 'name': 'alpha' }, + ], + }, + { + // R<enum:P> + 'returned': [], + 'in_args': [], + }, + { // "P" 'others': [ { 'path': 'generics', 'name': 'P' }, diff --git a/tests/rustdoc-js/primitive.js b/tests/rustdoc-js/primitive.js index 918f7099918..4aec98c3403 100644 --- a/tests/rustdoc-js/primitive.js +++ b/tests/rustdoc-js/primitive.js @@ -3,6 +3,8 @@ const QUERY = [ "i32", "str", + "primitive:str", + "struct:str", "TotoIsSomewhere", ]; @@ -18,6 +20,14 @@ const EXPECTED = [ ], }, { + 'returned': [ + { 'path': 'primitive', 'name': 'foo' }, + ], + }, + { + 'returned': [], + }, + { 'others': [], 'in_args': [], 'returned': [], diff --git a/tests/rustdoc-js/search-bag-semantics.js b/tests/rustdoc-js/search-bag-semantics.js new file mode 100644 index 00000000000..c56a3df5f90 --- /dev/null +++ b/tests/rustdoc-js/search-bag-semantics.js @@ -0,0 +1,20 @@ +// exact-check + +const QUERY = [ + 'P', + 'P, P', +]; + +const EXPECTED = [ + { + 'in_args': [ + { 'path': 'search_bag_semantics', 'name': 'alacazam' }, + { 'path': 'search_bag_semantics', 'name': 'abracadabra' }, + ], + }, + { + 'others': [ + { 'path': 'search_bag_semantics', 'name': 'abracadabra' }, + ], + }, +]; diff --git a/tests/rustdoc-js/search-bag-semantics.rs b/tests/rustdoc-js/search-bag-semantics.rs new file mode 100644 index 00000000000..546572dc4ef --- /dev/null +++ b/tests/rustdoc-js/search-bag-semantics.rs @@ -0,0 +1,4 @@ +pub struct P; + +pub fn abracadabra(a: P, b: P) {} +pub fn alacazam(a: P) {} diff --git a/tests/rustdoc-js/where-clause.js b/tests/rustdoc-js/where-clause.js index 6cb42a455a3..86254a80e20 100644 --- a/tests/rustdoc-js/where-clause.js +++ b/tests/rustdoc-js/where-clause.js @@ -1,4 +1,4 @@ -const QUERY = ['trait<nested>', '-> trait<nested>', 't1, t2']; +const QUERY = ['trait<nested>', '-> trait<nested>', 't1, t2', '-> shazam', 'drizzel -> shazam']; const EXPECTED = [ { @@ -16,4 +16,15 @@ const EXPECTED = [ { 'path': 'where_clause', 'name': 'presto' }, ], }, + { + 'others': [ + { 'path': 'where_clause', 'name': 'bippety' }, + { 'path': 'where_clause::Drizzel', 'name': 'boppety' }, + ], + }, + { + 'others': [ + { 'path': 'where_clause::Drizzel', 'name': 'boppety' }, + ], + }, ]; diff --git a/tests/rustdoc-js/where-clause.rs b/tests/rustdoc-js/where-clause.rs index 808561feee2..56c01019fb6 100644 --- a/tests/rustdoc-js/where-clause.rs +++ b/tests/rustdoc-js/where-clause.rs @@ -14,3 +14,17 @@ pub trait T2<'a, T> { } pub fn presto<A, B>(_: A, _: B) where A: T1, B: for <'b> T2<'b, Nested> {} + +pub trait Shazam {} + +pub fn bippety<X>() -> &'static X where X: Shazam { + panic!() +} + +pub struct Drizzel<T>(T); + +impl<T> Drizzel<T> { + pub fn boppety(&self) -> &T where T: Shazam { + panic!(); + } +} diff --git a/tests/rustdoc-json/fns/extern_c_variadic.rs b/tests/rustdoc-json/fns/extern_c_variadic.rs new file mode 100644 index 00000000000..33bebbab5e0 --- /dev/null +++ b/tests/rustdoc-json/fns/extern_c_variadic.rs @@ -0,0 +1,9 @@ +#![feature(no_core)] +#![no_core] + +extern "C" { + // @is "$.index[*][?(@.name == 'not_variadic')].inner.decl.c_variadic" false + pub fn not_variadic(_: i32); + // @is "$.index[*][?(@.name == 'variadic')].inner.decl.c_variadic" true + pub fn variadic(_: i32, ...); +} diff --git a/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs new file mode 100644 index 00000000000..15bf51e6f8e --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs @@ -0,0 +1 @@ +//! Inner doc comment diff --git a/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs b/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs new file mode 100644 index 00000000000..4d6a3256645 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs @@ -0,0 +1,10 @@ +// Test for issue #108501. +// Module parent scope doesn't hijack import's parent scope for the import's doc links. + +// check-pass +// aux-build: inner-crate-doc.rs +// compile-flags: --extern inner_crate_doc --edition 2018 + +/// Import doc comment [inner_crate_doc] +#[doc(inline)] +pub use inner_crate_doc; diff --git a/tests/rustdoc-ui/intra-doc/import-inline-merge.rs b/tests/rustdoc-ui/intra-doc/import-inline-merge.rs new file mode 100644 index 00000000000..31fef032b0f --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/import-inline-merge.rs @@ -0,0 +1,16 @@ +// Import for `A` is inlined and doc comments on the import and `A` itself are merged. +// After the merge they still have correct parent scopes to resolve both `[A]` and `[B]`. + +// check-pass + +#![allow(rustdoc::private_intra_doc_links)] + +mod m { + /// [B] + pub struct A {} + + pub struct B {} +} + +/// [A] +pub use m::A; diff --git a/tests/rustdoc-ui/intra-doc/reachable-non-exported.rs b/tests/rustdoc-ui/intra-doc/reachable-non-exported.rs new file mode 100644 index 00000000000..6afcad4f921 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/reachable-non-exported.rs @@ -0,0 +1,13 @@ +// The structure is reachable, but not exported, so rustdoc +// doesn't attempt to request doc link resolutions on it. + +// check-pass + +mod private { + /// [core::str::FromStr] + pub struct ReachableButNotExported; +} + +pub fn foo() -> private::ReachableButNotExported { + private::ReachableButNotExported +} diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 79e6b94f1ac..72f5f933d8d 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -44,6 +44,7 @@ -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries -Z extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no) -Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no) + -Z flatten-format-args=val -- flatten nested format_args!() and literals into a simplified format_args!() call (default: no) -Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no) -Z fuel=val -- set the optimization fuel quota for a crate -Z function-sections=val -- whether each function should go in its own section @@ -182,6 +183,7 @@ -Z threads=val -- use a thread pool with N threads -Z time-llvm-passes=val -- measure time of each LLVM pass (default: no) -Z time-passes=val -- measure time of each rustc pass (default: no) + -Z time-passes-format=val -- the format to use for -Z time-passes (`text` (default) or `json`) -Z tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests -Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details) -Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no) diff --git a/tests/rustdoc/deprecated.rs b/tests/rustdoc/deprecated.rs index 51860441b35..9c9c0945b8f 100644 --- a/tests/rustdoc/deprecated.rs +++ b/tests/rustdoc/deprecated.rs @@ -28,6 +28,6 @@ pub struct V; pub struct W; // @matches deprecated/struct.X.html '//*[@class="stab deprecated"]' \ -// 'Deprecated: shorthand reason$' -#[deprecated = "shorthand reason"] +// 'Deprecated: shorthand reason: code$' +#[deprecated = "shorthand reason: `code`"] pub struct X; diff --git a/tests/rustdoc/footnote-in-summary.rs b/tests/rustdoc/footnote-in-summary.rs new file mode 100644 index 00000000000..e6ff5a7fd51 --- /dev/null +++ b/tests/rustdoc/footnote-in-summary.rs @@ -0,0 +1,17 @@ +// This test ensures that no footnote reference is generated inside +// summary doc. + +#![crate_name = "foo"] + +// @has 'foo/index.html' +// @has - '//*[@class="desc docblock-short"]' 'hello bla' +// @!has - '//*[@class="desc docblock-short"]/sup' '1' + +// @has 'foo/struct.S.html' +// @has - '//*[@class="docblock"]//sup' '1' +// @has - '//*[@class="docblock"]' 'hello 1 bla' + +/// hello [^foot] bla +/// +/// [^foot]: blabla +pub struct S; diff --git a/tests/rustdoc/intra-doc/prim-methods.rs b/tests/rustdoc/intra-doc/prim-methods.rs index a412a23fda8..bc1965aac55 100644 --- a/tests/rustdoc/intra-doc/prim-methods.rs +++ b/tests/rustdoc/intra-doc/prim-methods.rs @@ -2,6 +2,8 @@ // @has prim_methods/index.html // @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char' +// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]/@title' 'primitive char' // @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8' +// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]/@title' 'method char::len_utf8' //! A [`char`] and its [`char::len_utf8`]. diff --git a/tests/rustdoc/issue-109258-missing-private-inlining.rs b/tests/rustdoc/issue-109258-missing-private-inlining.rs new file mode 100644 index 00000000000..96f606368b2 --- /dev/null +++ b/tests/rustdoc/issue-109258-missing-private-inlining.rs @@ -0,0 +1,27 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/109258>. + +#![crate_name = "foo"] + +// @has 'foo/index.html' +// We should only have a "Re-exports" and a "Modules" headers. +// @count - '//*[@id="main-content"]/h2[@class="small-section-header"]' 2 +// @has - '//*[@id="main-content"]/h2[@class="small-section-header"]' 'Re-exports' +// @has - '//*[@id="main-content"]/h2[@class="small-section-header"]' 'Modules' + +// @has - '//*[@id="reexport.Foo"]' 'pub use crate::issue_109258::Foo;' +// @has - '//*[@id="reexport.Foo"]//a[@href="issue_109258/struct.Foo.html"]' 'Foo' +// @!has 'foo/struct.Foo.html' +pub use crate::issue_109258::Foo; + +// @has 'foo/issue_109258/index.html' +// We should only have a "Structs" header. +// @count - '//*[@id="main-content"]/h2[@class="small-section-header"]' 1 +// @has - '//*[@id="main-content"]/h2[@class="small-section-header"]' 'Structs' +// @has - '//*[@id="main-content"]//a[@href="struct.Foo.html"]' 'Foo' +// @has 'foo/issue_109258/struct.Foo.html' +pub mod issue_109258 { + mod priv_mod { + pub struct Foo; + } + pub use self::priv_mod::Foo; +} diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs index bfce46cf444..bfce46cf444 100644 --- a/tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs index b359dcea0ff..b359dcea0ff 100644 --- a/tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs diff --git a/tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html index 46be00a0804..46be00a0804 100644 --- a/tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html diff --git a/tests/rustdoc/doc-notable_trait-slice.rs b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs index 2411da8cd45..ef206710b4b 100644 --- a/tests/rustdoc/doc-notable_trait-slice.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs @@ -18,3 +18,9 @@ pub fn bare_fn_matches() -> &'static [SomeStruct] { pub fn bare_fn_no_matches() -> &'static [OtherStruct] { &[] } + +// @has doc_notable_trait_slice/fn.bare_fn_mut_no_matches.html +// @count - '//script[@id="notable-traits-data"]' 0 +pub fn bare_fn_mut_no_matches() -> &'static mut [SomeStruct] { + &mut [] +} diff --git a/tests/rustdoc/doc-notable_trait.bare-fn.html b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html index f592e3b375c..f592e3b375c 100644 --- a/tests/rustdoc/doc-notable_trait.bare-fn.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html diff --git a/tests/rustdoc/doc-notable_trait.rs b/tests/rustdoc/notable-trait/doc-notable_trait.rs index d8941769fa6..d8941769fa6 100644 --- a/tests/rustdoc/doc-notable_trait.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait.rs diff --git a/tests/rustdoc/doc-notable_trait.some-struct-new.html b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html index e8f4f600045..e8f4f600045 100644 --- a/tests/rustdoc/doc-notable_trait.some-struct-new.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html diff --git a/tests/rustdoc/doc-notable_trait.wrap-me.html b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html index e7909669b15..e7909669b15 100644 --- a/tests/rustdoc/doc-notable_trait.wrap-me.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html diff --git a/tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs index 3fb00c7db84..3fb00c7db84 100644 --- a/tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc/notable-trait/notable-trait-generics.rs new file mode 100644 index 00000000000..611902abad6 --- /dev/null +++ b/tests/rustdoc/notable-trait/notable-trait-generics.rs @@ -0,0 +1,35 @@ +#![feature(doc_notable_trait)] + +// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and +// the return type has a generic type. +pub mod generic_return { + pub struct Wrapper<T>(T); + + #[doc(notable_trait)] + pub trait NotableTrait {} + + impl NotableTrait for Wrapper<u8> {} + + // @has notable_trait_generics/generic_return/fn.returning.html + // @!has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<T>' + pub fn returning<T>() -> Wrapper<T> { + loop {} + } +} + +// Notable traits SHOULD be shown when the `impl` has a generic type and the +// return type has a concrete type. +pub mod generic_impl { + pub struct Wrapper<T>(T); + + #[doc(notable_trait)] + pub trait NotableTrait {} + + impl<T> NotableTrait for Wrapper<T> {} + + // @has notable_trait_generics/generic_impl/fn.returning.html + // @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<u8>' + pub fn returning() -> Wrapper<u8> { + loop {} + } +} diff --git a/tests/rustdoc/spotlight-from-dependency.odd.html b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html index 5f54b7522ae..5f54b7522ae 100644 --- a/tests/rustdoc/spotlight-from-dependency.odd.html +++ b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html diff --git a/tests/rustdoc/spotlight-from-dependency.rs b/tests/rustdoc/notable-trait/spotlight-from-dependency.rs index 426759c7bf8..426759c7bf8 100644 --- a/tests/rustdoc/spotlight-from-dependency.rs +++ b/tests/rustdoc/notable-trait/spotlight-from-dependency.rs diff --git a/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs deleted file mode 100644 index a3b570ad8c4..00000000000 --- a/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ /dev/null @@ -1,80 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_lint; -extern crate rustc_span; -#[macro_use] -extern crate rustc_session; -extern crate rustc_ast; - -use rustc_ast::attr; -use rustc_driver::plugin::Registry; -use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::symbol::Symbol; - -macro_rules! fake_lint_pass { - ($struct:ident, $($attr:expr),*) => { - struct $struct; - - impl LintPass for $struct { - fn name(&self) -> &'static str { - stringify!($struct) - } - } - - impl LateLintPass<'_> for $struct { - fn check_crate(&mut self, cx: &LateContext) { - let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let span = cx.tcx.def_span(CRATE_DEF_ID); - $( - if !cx.sess().contains_name(attrs, $attr) { - cx.lint(CRATE_NOT_OKAY, |lint| { - let msg = format!("crate is not marked with #![{}]", $attr); - lint.build(&msg).set_span(span).emit(); - }); - } - )* - } - } - - } -} - -declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); -declare_lint!(CRATE_NOT_RED, Warn, "crate not marked with #![crate_red]"); -declare_lint!(CRATE_NOT_BLUE, Warn, "crate not marked with #![crate_blue]"); -declare_lint!(CRATE_NOT_GREY, Warn, "crate not marked with #![crate_grey]"); -declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]"); - -fake_lint_pass! { - PassOkay, - Symbol::intern("crate_okay") -} - -fake_lint_pass! { - PassRedBlue, - Symbol::intern("crate_red"), Symbol::intern("crate_blue") -} - -fake_lint_pass! { - PassGreyGreen, - Symbol::intern("crate_grey"), Symbol::intern("crate_green") -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[ - &CRATE_NOT_OKAY, - &CRATE_NOT_RED, - &CRATE_NOT_BLUE, - &CRATE_NOT_GREY, - &CRATE_NOT_GREEN, - ]); - reg.lint_store.register_late_pass(|_| Box::new(PassOkay)); - reg.lint_store.register_late_pass(|_| Box::new(PassRedBlue)); - reg.lint_store.register_late_pass(|_| Box::new(PassGreyGreen)); -} diff --git a/tests/ui-fulldeps/auxiliary/lint-for-crate.rs b/tests/ui-fulldeps/auxiliary/lint-for-crate.rs index 073da688c7c..6304c07d2c7 100644 --- a/tests/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/tests/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -4,13 +4,13 @@ extern crate rustc_driver; extern crate rustc_hir; -#[macro_use] extern crate rustc_lint; #[macro_use] extern crate rustc_session; extern crate rustc_ast; extern crate rustc_span; +use rustc_ast::attr; use rustc_driver::plugin::Registry; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_span::def_id::CRATE_DEF_ID; @@ -28,12 +28,10 @@ impl<'tcx> LateLintPass<'tcx> for Pass { fn check_crate(&mut self, cx: &LateContext) { let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); let span = cx.tcx.def_span(CRATE_DEF_ID); - if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) { - cx.lint( - CRATE_NOT_OKAY, - "crate is not marked with #![crate_okay]", - |lint| lint.set_span(span) - ); + if !attr::contains_name(attrs, Symbol::intern("crate_okay")) { + cx.lint(CRATE_NOT_OKAY, "crate is not marked with #![crate_okay]", |lint| { + lint.set_span(span) + }); } } } diff --git a/tests/ui/associated-consts/issue-93775.rs b/tests/ui/associated-consts/issue-93775.rs index 7a007b732de..db788fe6e6a 100644 --- a/tests/ui/associated-consts/issue-93775.rs +++ b/tests/ui/associated-consts/issue-93775.rs @@ -3,7 +3,7 @@ // Regression for #93775, needs build-pass to test it. -#![recursion_limit = "1000"] +#![recursion_limit = "1001"] use std::marker::PhantomData; diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs new file mode 100644 index 00000000000..6f95273116b --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299-1.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types, non_lifetime_binders, type_alias_impl_trait)] +#![allow(incomplete_features)] + +struct Lexer<T>(T); + +impl Lexer<i32> { + type Cursor = (); +} + +type X = impl for<T> Fn() -> Lexer<T>::Cursor; //~ ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope + +fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr new file mode 100644 index 00000000000..dc59b56ee20 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr @@ -0,0 +1,15 @@ +error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope + --> $DIR/issue-109299-1.rs:10:40 + | +LL | struct Lexer<T>(T); + | --------------- associated item `Cursor` not found for this struct +... +LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor; + | ^^^^^^ associated item not found in `Lexer<T>` + | + = note: the associated type was found for + - `Lexer<i32>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/issue-109299.rs b/tests/ui/associated-inherent-types/issue-109299.rs new file mode 100644 index 00000000000..84e4f9e7252 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct Lexer<'d>(&'d ()); + +impl Lexer<'d> { //~ ERROR use of undeclared lifetime name `'d` + type Cursor = (); +} + +fn test(_: Lexer::Cursor) {} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299.stderr b/tests/ui/associated-inherent-types/issue-109299.stderr new file mode 100644 index 00000000000..63f50732d3c --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299.stderr @@ -0,0 +1,11 @@ +error[E0261]: use of undeclared lifetime name `'d` + --> $DIR/issue-109299.rs:6:12 + | +LL | impl Lexer<'d> { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'d` here: `<'d>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/async-await/async-trait-fn.current.stderr b/tests/ui/async-await/async-trait-fn.current.stderr new file mode 100644 index 00000000000..7ccf2f2301d --- /dev/null +++ b/tests/ui/async-await/async-trait-fn.current.stderr @@ -0,0 +1,42 @@ +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:6:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:7:5 + | +LL | async fn bar(&self) {} + | -----^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:8:5 + | +LL | async fn baz() { + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/async-trait-fn.next.stderr b/tests/ui/async-await/async-trait-fn.next.stderr new file mode 100644 index 00000000000..7ccf2f2301d --- /dev/null +++ b/tests/ui/async-await/async-trait-fn.next.stderr @@ -0,0 +1,42 @@ +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:6:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:7:5 + | +LL | async fn bar(&self) {} + | -----^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:8:5 + | +LL | async fn baz() { + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/async-trait-fn.rs b/tests/ui/async-await/async-trait-fn.rs index e2062e82725..04123badb53 100644 --- a/tests/ui/async-await/async-trait-fn.rs +++ b/tests/ui/async-await/async-trait-fn.rs @@ -1,4 +1,5 @@ // edition:2018 + trait T { async fn foo() {} //~ ERROR functions in traits cannot be declared `async` async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async` diff --git a/tests/ui/async-await/async-trait-fn.stderr b/tests/ui/async-await/async-trait-fn.stderr index afbe25cf7ab..68ebe3507ac 100644 --- a/tests/ui/async-await/async-trait-fn.stderr +++ b/tests/ui/async-await/async-trait-fn.stderr @@ -1,5 +1,5 @@ error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:3:5 + --> $DIR/async-trait-fn.rs:4:5 | LL | async fn foo() {} | -----^^^^^^^^^ @@ -12,7 +12,7 @@ LL | async fn foo() {} = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:4:5 + --> $DIR/async-trait-fn.rs:5:5 | LL | async fn bar(&self) {} | -----^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | async fn bar(&self) {} = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:5:5 + --> $DIR/async-trait-fn.rs:6:5 | LL | async fn baz() { | -----^^^^^^^^^ diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr index ba918eb28de..c47b99e657e 100644 --- a/tests/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr @@ -1,5 +1,5 @@ error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:3:1 + --> $DIR/edition-deny-async-fns-2015.rs:5:1 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -8,7 +8,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:5:12 + --> $DIR/edition-deny-async-fns-2015.rs:7:12 | LL | fn baz() { async fn foo() {} } | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -17,7 +17,7 @@ LL | fn baz() { async fn foo() {} } = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:7:1 + --> $DIR/edition-deny-async-fns-2015.rs:9:1 | LL | async fn async_baz() { | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -26,7 +26,7 @@ LL | async fn async_baz() { = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:8:5 + --> $DIR/edition-deny-async-fns-2015.rs:10:5 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -35,7 +35,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:14:5 + --> $DIR/edition-deny-async-fns-2015.rs:16:5 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -44,7 +44,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:18:5 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -53,7 +53,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:36:9 + --> $DIR/edition-deny-async-fns-2015.rs:38:9 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -62,7 +62,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:26:9 + --> $DIR/edition-deny-async-fns-2015.rs:28:9 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -71,7 +71,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:31:13 + --> $DIR/edition-deny-async-fns-2015.rs:33:13 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -80,7 +80,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0706]: functions in traits cannot be declared `async` - --> $DIR/edition-deny-async-fns-2015.rs:18:5 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 | LL | async fn foo() {} | -----^^^^^^^^^ diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr new file mode 100644 index 00000000000..c47b99e657e --- /dev/null +++ b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr @@ -0,0 +1,98 @@ +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:5:1 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:7:12 + | +LL | fn baz() { async fn foo() {} } + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:9:1 + | +LL | async fn async_baz() { + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:10:5 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:16:5 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:38:9 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:28:9 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:33:13 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0670, E0706. +For more information about an error, try `rustc --explain E0670`. diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.rs b/tests/ui/async-await/edition-deny-async-fns-2015.rs index 6bd6d879a4a..d4c30dc9d82 100644 --- a/tests/ui/async-await/edition-deny-async-fns-2015.rs +++ b/tests/ui/async-await/edition-deny-async-fns-2015.rs @@ -1,4 +1,6 @@ // edition:2015 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.stderr b/tests/ui/async-await/in-trait/async-default-fn-overridden.current.stderr index 61a826258d0..2142ee232ca 100644 --- a/tests/ui/async-await/in-trait/async-default-fn-overridden.stderr +++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/async-default-fn-overridden.rs:4:12 + --> $DIR/async-default-fn-overridden.rs:6:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr b/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr new file mode 100644 index 00000000000..2142ee232ca --- /dev/null +++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/async-default-fn-overridden.rs:6:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs index 0fd1a2703db..dd1af93d706 100644 --- a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs +++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs @@ -1,5 +1,7 @@ // run-pass // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.current.stderr index f1f0d7e5907..780da068962 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.current.stderr @@ -1,33 +1,33 @@ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics-and-bounds.rs:12:28 + --> $DIR/async-generics-and-bounds.rs:14:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ | note: the parameter type `U` must be valid for the anonymous lifetime defined here... - --> $DIR/async-generics-and-bounds.rs:12:18 + --> $DIR/async-generics-and-bounds.rs:14:18 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at - --> $DIR/async-generics-and-bounds.rs:12:28 + --> $DIR/async-generics-and-bounds.rs:14:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics-and-bounds.rs:12:28 + --> $DIR/async-generics-and-bounds.rs:14:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ | note: the parameter type `T` must be valid for the anonymous lifetime defined here... - --> $DIR/async-generics-and-bounds.rs:12:18 + --> $DIR/async-generics-and-bounds.rs:14:18 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at - --> $DIR/async-generics-and-bounds.rs:12:28 + --> $DIR/async-generics-and-bounds.rs:14:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr new file mode 100644 index 00000000000..780da068962 --- /dev/null +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr @@ -0,0 +1,37 @@ +error[E0311]: the parameter type `U` may not live long enough + --> $DIR/async-generics-and-bounds.rs:14:28 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^^^ + | +note: the parameter type `U` must be valid for the anonymous lifetime defined here... + --> $DIR/async-generics-and-bounds.rs:14:18 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^ +note: ...so that the reference type `&(T, U)` does not outlive the data it points at + --> $DIR/async-generics-and-bounds.rs:14:28 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^^^ + +error[E0311]: the parameter type `T` may not live long enough + --> $DIR/async-generics-and-bounds.rs:14:28 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^^^ + | +note: the parameter type `T` must be valid for the anonymous lifetime defined here... + --> $DIR/async-generics-and-bounds.rs:14:18 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^ +note: ...so that the reference type `&(T, U)` does not outlive the data it points at + --> $DIR/async-generics-and-bounds.rs:14:28 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0311`. diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs index a73d55adfec..146e74ec2d0 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs @@ -1,6 +1,8 @@ // check-fail // known-bug: #102682 // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.current.stderr index 2f05564564c..04e1ab6d769 100644 --- a/tests/ui/async-await/in-trait/async-generics.stderr +++ b/tests/ui/async-await/in-trait/async-generics.current.stderr @@ -1,33 +1,33 @@ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics.rs:9:28 + --> $DIR/async-generics.rs:11:28 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ | note: the parameter type `U` must be valid for the anonymous lifetime defined here... - --> $DIR/async-generics.rs:9:18 + --> $DIR/async-generics.rs:11:18 | LL | async fn foo(&self) -> &(T, U); | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at - --> $DIR/async-generics.rs:9:28 + --> $DIR/async-generics.rs:11:28 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics.rs:9:28 + --> $DIR/async-generics.rs:11:28 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ | note: the parameter type `T` must be valid for the anonymous lifetime defined here... - --> $DIR/async-generics.rs:9:18 + --> $DIR/async-generics.rs:11:18 | LL | async fn foo(&self) -> &(T, U); | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at - --> $DIR/async-generics.rs:9:28 + --> $DIR/async-generics.rs:11:28 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-generics.next.stderr b/tests/ui/async-await/in-trait/async-generics.next.stderr new file mode 100644 index 00000000000..04e1ab6d769 --- /dev/null +++ b/tests/ui/async-await/in-trait/async-generics.next.stderr @@ -0,0 +1,37 @@ +error[E0311]: the parameter type `U` may not live long enough + --> $DIR/async-generics.rs:11:28 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^^^ + | +note: the parameter type `U` must be valid for the anonymous lifetime defined here... + --> $DIR/async-generics.rs:11:18 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^ +note: ...so that the reference type `&(T, U)` does not outlive the data it points at + --> $DIR/async-generics.rs:11:28 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^^^ + +error[E0311]: the parameter type `T` may not live long enough + --> $DIR/async-generics.rs:11:28 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^^^ + | +note: the parameter type `T` must be valid for the anonymous lifetime defined here... + --> $DIR/async-generics.rs:11:18 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^ +note: ...so that the reference type `&(T, U)` does not outlive the data it points at + --> $DIR/async-generics.rs:11:28 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0311`. diff --git a/tests/ui/async-await/in-trait/async-generics.rs b/tests/ui/async-await/in-trait/async-generics.rs index 67000e5770e..507500abf4e 100644 --- a/tests/ui/async-await/in-trait/async-generics.rs +++ b/tests/ui/async-await/in-trait/async-generics.rs @@ -1,6 +1,8 @@ // check-fail // known-bug: #102682 // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/async-await/in-trait/generics-mismatch.current.stderr b/tests/ui/async-await/in-trait/generics-mismatch.current.stderr new file mode 100644 index 00000000000..be23384e049 --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.current.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:13:18 + | +LL | trait Foo { + | --- +LL | async fn foo<T>(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo<const N: usize>() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/generics-mismatch.next.stderr b/tests/ui/async-await/in-trait/generics-mismatch.next.stderr new file mode 100644 index 00000000000..be23384e049 --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.next.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:13:18 + | +LL | trait Foo { + | --- +LL | async fn foo<T>(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo<const N: usize>() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs new file mode 100644 index 00000000000..fc29783c0e3 --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.rs @@ -0,0 +1,15 @@ +// edition: 2021 + +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + async fn foo<T>(); +} + +impl Foo for () { + async fn foo<const N: usize>() {} + //~^ ERROR: method `foo` has an incompatible generic parameter for trait `Foo` [E0053] +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/generics-mismatch.stderr b/tests/ui/async-await/in-trait/generics-mismatch.stderr new file mode 100644 index 00000000000..3518aa05cec --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:11:18 + | +LL | trait Foo { + | --- +LL | async fn foo<T>(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo<const N: usize>() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/issue-102310.rs b/tests/ui/async-await/in-trait/issue-102310.rs index 49c3e9feeb4..8e5dbd08eb9 100644 --- a/tests/ui/async-await/in-trait/issue-102310.rs +++ b/tests/ui/async-await/in-trait/issue-102310.rs @@ -1,5 +1,7 @@ // check-pass // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/async-await/in-trait/issue-104678.rs b/tests/ui/async-await/in-trait/issue-104678.rs index e396df4e5d1..3d010f18009 100644 --- a/tests/ui/async-await/in-trait/issue-104678.rs +++ b/tests/ui/async-await/in-trait/issue-104678.rs @@ -1,5 +1,7 @@ // edition:2021 // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.stderr b/tests/ui/async-await/in-trait/lifetime-mismatch.current.stderr index d87adcc78b6..0e9477544a4 100644 --- a/tests/ui/async-await/in-trait/lifetime-mismatch.stderr +++ b/tests/ui/async-await/in-trait/lifetime-mismatch.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/lifetime-mismatch.rs:3:12 + --> $DIR/lifetime-mismatch.rs:5:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration - --> $DIR/lifetime-mismatch.rs:12:17 + --> $DIR/lifetime-mismatch.rs:14:17 | LL | async fn foo<'a>(&self); | ---- lifetimes in impl do not match this method in trait diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr b/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr new file mode 100644 index 00000000000..0e9477544a4 --- /dev/null +++ b/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr @@ -0,0 +1,21 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/lifetime-mismatch.rs:5:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/lifetime-mismatch.rs:14:17 + | +LL | async fn foo<'a>(&self); + | ---- lifetimes in impl do not match this method in trait +... +LL | async fn foo(&self) {} + | ^ lifetimes do not match method in trait + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0195`. diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.rs b/tests/ui/async-await/in-trait/lifetime-mismatch.rs index 45ede193c0f..5ff5a01a1ee 100644 --- a/tests/ui/async-await/in-trait/lifetime-mismatch.rs +++ b/tests/ui/async-await/in-trait/lifetime-mismatch.rs @@ -1,4 +1,6 @@ // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.current.stderr index 5cedf3ddb0f..319ed582e27 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.stderr +++ b/tests/ui/async-await/in-trait/missing-send-bound.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/missing-send-bound.rs:3:12 + --> $DIR/missing-send-bound.rs:5:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -8,19 +8,19 @@ LL | #![feature(async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error: future cannot be sent between threads safely - --> $DIR/missing-send-bound.rs:15:20 + --> $DIR/missing-send-bound.rs:17:20 | LL | assert_is_send(test::<T>()); | ^^^^^^^^^^^ future returned by `test` is not `Send` | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>` note: future is not `Send` as it awaits another future which is not `Send` - --> $DIR/missing-send-bound.rs:11:5 + --> $DIR/missing-send-bound.rs:13:5 | LL | T::bar().await; | ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send` note: required by a bound in `assert_is_send` - --> $DIR/missing-send-bound.rs:19:27 + --> $DIR/missing-send-bound.rs:21:27 | LL | fn assert_is_send(_: impl Send) {} | ^^^^ required by this bound in `assert_is_send` diff --git a/tests/ui/async-await/in-trait/missing-send-bound.next.stderr b/tests/ui/async-await/in-trait/missing-send-bound.next.stderr new file mode 100644 index 00000000000..319ed582e27 --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-send-bound.next.stderr @@ -0,0 +1,29 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/missing-send-bound.rs:5:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/missing-send-bound.rs:17:20 + | +LL | assert_is_send(test::<T>()); + | ^^^^^^^^^^^ future returned by `test` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/missing-send-bound.rs:13:5 + | +LL | T::bar().await; + | ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send` +note: required by a bound in `assert_is_send` + --> $DIR/missing-send-bound.rs:21:27 + | +LL | fn assert_is_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_is_send` + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs index 78922b59b27..705fcf322f9 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.rs +++ b/tests/ui/async-await/in-trait/missing-send-bound.rs @@ -1,4 +1,6 @@ // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.current.stderr index b8d83d0f28a..a5efc757156 100644 --- a/tests/ui/async-await/in-trait/return-type-suggestion.stderr +++ b/tests/ui/async-await/in-trait/return-type-suggestion.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/return-type-suggestion.rs:3:12 + --> $DIR/return-type-suggestion.rs:5:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/return-type-suggestion.rs:8:9 + --> $DIR/return-type-suggestion.rs:10:9 | LL | Ok(()) | ^^^^^^- help: consider using a semicolon here: `;` diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr new file mode 100644 index 00000000000..a5efc757156 --- /dev/null +++ b/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr @@ -0,0 +1,23 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/return-type-suggestion.rs:5:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/return-type-suggestion.rs:10:9 + | +LL | Ok(()) + | ^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `Result<(), _>` + | + = note: expected unit type `()` + found enum `Result<(), _>` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.rs b/tests/ui/async-await/in-trait/return-type-suggestion.rs index 3446761d119..3de66306d9a 100644 --- a/tests/ui/async-await/in-trait/return-type-suggestion.rs +++ b/tests/ui/async-await/in-trait/return-type-suggestion.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr index 245c3a40e05..f032ea779dd 100644 --- a/tests/ui/borrowck/issue-64453.stderr +++ b/tests/ui/borrowck/issue-64453.stderr @@ -1,4 +1,4 @@ -error: `Arguments::<'a>::new_v1` is not yet stable as a const fn +error: `Arguments::<'a>::new_const` is not yet stable as a const fn --> $DIR/issue-64453.rs:4:31 | LL | static settings_dir: String = format!(""); diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib.rs b/tests/ui/cfg/auxiliary/cfg_false_lib.rs new file mode 100644 index 00000000000..3c011d72b02 --- /dev/null +++ b/tests/ui/cfg/auxiliary/cfg_false_lib.rs @@ -0,0 +1,6 @@ +// It is unclear whether a fully unconfigured crate should link to standard library, +// or what its `no_std`/`no_core`/`compiler_builtins` status, more precisely. +// Currently the usual standard library prelude is added to such crates, +// and therefore they link to libstd. + +#![cfg(FALSE)] diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs new file mode 100644 index 00000000000..21ea3ec79b4 --- /dev/null +++ b/tests/ui/cfg/cfg-false-feature.rs @@ -0,0 +1,20 @@ +// It is unclear which features should be in effect in a fully unconfigured crate (issue #104633). +// Currently none on the features are in effect, so we get the feature gates reported. + +// check-pass +// compile-flags: --crate-type lib + +#![feature(decl_macro)] +#![cfg(FALSE)] +#![feature(box_syntax)] + +macro mac() {} //~ WARN `macro` is experimental + //~| WARN unstable syntax can change at any point in the future + +trait A = Clone; //~ WARN trait aliases are experimental + //~| WARN unstable syntax can change at any point in the future + +fn main() { + let box _ = Box::new(0); //~ WARN box pattern syntax is experimental + //~| WARN unstable syntax can change at any point in the future +} diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr new file mode 100644 index 00000000000..14673fbdb14 --- /dev/null +++ b/tests/ui/cfg/cfg-false-feature.stderr @@ -0,0 +1,35 @@ +warning: trait aliases are experimental + --> $DIR/cfg-false-feature.rs:14:1 + | +LL | trait A = Clone; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: `macro` is experimental + --> $DIR/cfg-false-feature.rs:11:1 + | +LL | macro mac() {} + | ^^^^^^^^^^^^^^ + | + = note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: box pattern syntax is experimental + --> $DIR/cfg-false-feature.rs:18:9 + | +LL | let box _ = Box::new(0); + | ^^^^^ + | + = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: 3 warnings emitted + diff --git a/tests/ui/cfg/cfg_false_no_std.rs b/tests/ui/cfg/cfg_false_no_std.rs new file mode 100644 index 00000000000..319ea078187 --- /dev/null +++ b/tests/ui/cfg/cfg_false_no_std.rs @@ -0,0 +1,11 @@ +// Currently no error because the panic handler is supplied by libstd linked though the empty +// library, but the desirable behavior is unclear (see comments in cfg_false_lib.rs). + +// check-pass +// aux-build: cfg_false_lib.rs + +#![no_std] + +extern crate cfg_false_lib as _; + +fn main() {} diff --git a/tests/ui/closures/issue-109188.rs b/tests/ui/closures/issue-109188.rs new file mode 100644 index 00000000000..cae1ced9958 --- /dev/null +++ b/tests/ui/closures/issue-109188.rs @@ -0,0 +1,22 @@ +enum Either { + One(X), + Two(X), +} + +struct X(Y); + +struct Y; + +fn consume_fnmut(f: &dyn FnMut()) { + f(); +} + +fn move_into_fnmut() { + let x = move_into_fnmut(); + consume_fnmut(&|| { + let Either::One(_t) = x; //~ ERROR mismatched types + let Either::Two(_t) = x; //~ ERROR mismatched types + }); +} + +fn main() { } diff --git a/tests/ui/closures/issue-109188.stderr b/tests/ui/closures/issue-109188.stderr new file mode 100644 index 00000000000..d52b516294f --- /dev/null +++ b/tests/ui/closures/issue-109188.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/issue-109188.rs:17:13 + | +LL | let Either::One(_t) = x; + | ^^^^^^^^^^^^^^^ - this expression has type `()` + | | + | expected `()`, found `Either` + +error[E0308]: mismatched types + --> $DIR/issue-109188.rs:18:13 + | +LL | let Either::Two(_t) = x; + | ^^^^^^^^^^^^^^^ - this expression has type `()` + | | + | expected `()`, found `Either` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/conditional-compilation/cfg-attr-multi-true.stderr b/tests/ui/conditional-compilation/cfg-attr-multi-true.stderr index fbfcd45652f..123ce71727f 100644 --- a/tests/ui/conditional-compilation/cfg-attr-multi-true.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-multi-true.stderr @@ -35,6 +35,10 @@ note: the lint level is defined here | LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = MustUseDeprecated::new(); + | +++++++ warning: 5 warnings emitted diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs new file mode 100644 index 00000000000..e13dfbacd24 --- /dev/null +++ b/tests/ui/const-generics/bad-subst-const-kind.rs @@ -0,0 +1,13 @@ +// incremental +#![crate_type = "lib"] + +trait Q { + const ASSOC: usize; +} + +impl<const N: u64> Q for [u8; N] { + //~^ ERROR mismatched types + const ASSOC: usize = 1; +} + +pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() } diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr new file mode 100644 index 00000000000..bd24f9140e4 --- /dev/null +++ b/tests/ui/const-generics/bad-subst-const-kind.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/bad-subst-const-kind.rs:8:31 + | +LL | impl<const N: u64> Q for [u8; N] { + | ^ expected `usize`, found `u64` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/const-arg-in-const-arg.full.stderr b/tests/ui/const-generics/const-arg-in-const-arg.full.stderr index 8672e79b3e8..463a37d7e3d 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.full.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.full.stderr @@ -1,4 +1,4 @@ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:18:23 | LL | let _: [u8; faz::<'a>(&())]; @@ -10,7 +10,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:21:23 | LL | let _: [u8; faz::<'b>(&())]; @@ -22,7 +22,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:41:24 | LL | let _: Foo<{ faz::<'a>(&()) }>; @@ -34,7 +34,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:44:24 | LL | let _: Foo<{ faz::<'b>(&()) }>; @@ -94,7 +94,7 @@ LL | let _ = [0; bar::<N>()]; | = help: try adding a `where` bound using this expression: `where [(); bar::<N>()]:` -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:30:23 | LL | let _ = [0; faz::<'a>(&())]; @@ -106,7 +106,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:33:23 | LL | let _ = [0; faz::<'b>(&())]; @@ -134,7 +134,7 @@ LL | let _ = Foo::<{ bar::<N>() }>; | = help: try adding a `where` bound using this expression: `where [(); { bar::<N>() }]:` -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:52:27 | LL | let _ = Foo::<{ faz::<'a>(&()) }>; @@ -146,7 +146,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:55:27 | LL | let _ = Foo::<{ faz::<'b>(&()) }>; @@ -160,3 +160,4 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } error: aborting due to 16 previous errors +For more information about this error, try `rustc --explain E0794`. diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr index f1353aa9943..a7bd9c62b0e 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -216,7 +216,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _: [u8; bar::<{ N }>()]; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:18:23 | LL | let _: [u8; faz::<'a>(&())]; @@ -228,7 +228,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:21:23 | LL | let _: [u8; faz::<'b>(&())]; @@ -251,7 +251,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _: Foo<{ bar::<{ N }>() }>; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:41:24 | LL | let _: Foo<{ faz::<'a>(&()) }>; @@ -263,7 +263,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:44:24 | LL | let _: Foo<{ faz::<'b>(&()) }>; @@ -294,7 +294,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _ = [0; bar::<{ N }>()]; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:30:23 | LL | let _ = [0; faz::<'a>(&())]; @@ -306,7 +306,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:33:23 | LL | let _ = [0; faz::<'b>(&())]; @@ -329,7 +329,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _ = Foo::<{ bar::<{ N }>() }>; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:52:27 | LL | let _ = Foo::<{ faz::<'a>(&()) }>; @@ -341,7 +341,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:55:27 | LL | let _ = Foo::<{ faz::<'b>(&()) }>; @@ -355,5 +355,5 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } error: aborting due to 36 previous errors -Some errors have detailed explanations: E0658, E0747. +Some errors have detailed explanations: E0658, E0747, E0794. For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr index 7b4d46b8209..6b3396a25cf 100644 --- a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr +++ b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr @@ -1,8 +1,8 @@ error: unconstrained generic constant - --> $DIR/cross_crate_predicate.rs:7:13 + --> $DIR/cross_crate_predicate.rs:7:44 | LL | let _ = const_evaluatable_lib::test1::<T>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:` note: required by a bound in `test1` @@ -12,10 +12,10 @@ LL | [u8; std::mem::size_of::<T>() - 1]: Sized, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` error: unconstrained generic constant - --> $DIR/cross_crate_predicate.rs:7:13 + --> $DIR/cross_crate_predicate.rs:7:44 | LL | let _ = const_evaluatable_lib::test1::<T>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:` note: required by a bound in `test1` diff --git a/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs new file mode 100644 index 00000000000..734a3786294 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs @@ -0,0 +1,11 @@ +#![feature(generic_const_exprs)] +//~^ WARN the feature `generic_const_exprs` is incomplete + +trait B { + type U<T>; +} + +fn f<T: B<U<1i32> = ()>>() {} +//~^ ERROR constant provided when a type was expected + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr new file mode 100644 index 00000000000..8b6eb5b7594 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr @@ -0,0 +1,18 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/mismatched-gat-subst-kind.rs:1:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0747]: constant provided when a type was expected + --> $DIR/mismatched-gat-subst-kind.rs:8:13 + | +LL | fn f<T: B<U<1i32> = ()>>() {} + | ^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs new file mode 100644 index 00000000000..64317b9d39a --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs @@ -0,0 +1,52 @@ +// check-pass +// known-bug: #97156 + +#![feature(const_type_id, generic_const_exprs)] +#![allow(incomplete_features)] + +use std::any::TypeId; +// `One` and `Two` are currently considered equal types, as both +// `One <: Two` and `One :> Two` holds. +type One = for<'a> fn(&'a (), &'a ()); +type Two = for<'a, 'b> fn(&'a (), &'b ()); +trait AssocCt { + const ASSOC: usize; +} +const fn to_usize<T: 'static>() -> usize { + const WHAT_A_TYPE: TypeId = TypeId::of::<One>(); + match TypeId::of::<T>() { + WHAT_A_TYPE => 0, + _ => 1000, + } +} +impl<T: 'static> AssocCt for T { + const ASSOC: usize = to_usize::<T>(); +} + +trait WithAssoc<U> { + type Assoc; +} +impl<T: 'static> WithAssoc<()> for T where [(); <T as AssocCt>::ASSOC]: { + type Assoc = [u8; <T as AssocCt>::ASSOC]; +} + +fn generic<T: 'static, U>(x: <T as WithAssoc<U>>::Assoc) -> <T as WithAssoc<U>>::Assoc +where + [(); <T as AssocCt>::ASSOC]:, + T: WithAssoc<U>, +{ + x +} + + +fn unsound<T>(x: <One as WithAssoc<T>>::Assoc) -> <Two as WithAssoc<T>>::Assoc +where + One: WithAssoc<T>, +{ + let x: <Two as WithAssoc<T>>::Assoc = generic::<One, T>(x); + x +} + +fn main() { + println!("{:?}", unsound::<()>([])); +} diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index 6d8955e411e..394dd44d40d 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -1,8 +1,8 @@ error: the constant `N` is not of type `u8` - --> $DIR/type_mismatch.rs:2:5 + --> $DIR/type_mismatch.rs:2:11 | LL | bar::<N>() - | ^^^^^^^^ + | ^ expected `u8`, found `usize` | note: required by a bound in `bar` --> $DIR/type_mismatch.rs:6:8 diff --git a/tests/ui/consts/const-eval/format.rs b/tests/ui/consts/const-eval/format.rs index 0d8b7c12d8a..5bdb2bf1954 100644 --- a/tests/ui/consts/const-eval/format.rs +++ b/tests/ui/consts/const-eval/format.rs @@ -1,12 +1,13 @@ const fn failure() { panic!("{:?}", 0); //~^ ERROR cannot call non-const formatting macro in constant functions + //~| ERROR cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions } const fn print() { println!("{:?}", 0); //~^ ERROR cannot call non-const formatting macro in constant functions - //~| ERROR `Arguments::<'a>::new_v1` is not yet stable as a const fn + //~| ERROR cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions //~| ERROR cannot call non-const fn `_print` in constant functions } diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index 4bf39db5874..c39920d444d 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -7,8 +7,17 @@ LL | panic!("{:?}", 0); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0015]: cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions + --> $DIR/format.rs:2:5 + | +LL | panic!("{:?}", 0); + | ^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:7:22 + --> $DIR/format.rs:8:22 | LL | println!("{:?}", 0); | ^ @@ -16,17 +25,17 @@ LL | println!("{:?}", 0); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `Arguments::<'a>::new_v1` is not yet stable as a const fn - --> $DIR/format.rs:7:5 +error[E0015]: cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions + --> $DIR/format.rs:8:5 | LL | println!("{:?}", 0); | ^^^^^^^^^^^^^^^^^^^ | - = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `_print` in constant functions - --> $DIR/format.rs:7:5 + --> $DIR/format.rs:8:5 | LL | println!("{:?}", 0); | ^^^^^^^^^^^^^^^^^^^ @@ -63,19 +72,19 @@ LL | panic!("{:?}", 0); = note: this note originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant used - --> $DIR/format.rs:7:14 + --> $DIR/format.rs:8:14 | LL | println!("{:?}", 0); | ^^^^^^ note: erroneous constant used - --> $DIR/format.rs:7:14 + --> $DIR/format.rs:8:14 | LL | println!("{:?}", 0); | ^^^^^^ note: erroneous constant used - --> $DIR/format.rs:7:22 + --> $DIR/format.rs:8:22 | LL | println!("{:?}", 0); | ^ @@ -83,13 +92,13 @@ LL | println!("{:?}", 0); = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant used - --> $DIR/format.rs:7:22 + --> $DIR/format.rs:8:22 | LL | println!("{:?}", 0); | ^ | = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.rs b/tests/ui/consts/const-eval/panic-assoc-never-type.rs index 28edf514402..1abe708d19e 100644 --- a/tests/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.rs @@ -11,5 +11,5 @@ impl PrintName { } fn main() { - let _ = PrintName::VOID; //~ constant + let _ = PrintName::VOID; //~ erroneous constant used } diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.rs b/tests/ui/consts/const-eval/transmute-size-mismatch.rs new file mode 100644 index 00000000000..2410baea28c --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.rs @@ -0,0 +1,24 @@ +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +// These cases are statically rejected by `mem::transmute`, so we need custom +// MIR to be able to get to constant evaluation. +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime", phase = "initial")] +const unsafe fn mir_transmute<T, U>(x: T) -> U { + mir!{ + { + RET = CastTransmute(x); + //~^ ERROR evaluation of constant value failed + //~| ERROR evaluation of constant value failed + Return() + } + } +} + +const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; + +const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; + +fn main() {} diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr new file mode 100644 index 00000000000..e051491d343 --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr @@ -0,0 +1,37 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 4-byte type to 2-byte type: `i32` -> `u16` + | +note: inside `mir_transmute::<i32, u16>` + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FROM_BIGGER` + --> $DIR/transmute-size-mismatch.rs:20:35 + | +LL | const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 2-byte type to 4-byte type: `i16` -> `u32` + | +note: inside `mir_transmute::<i16, u32>` + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FROM_SMALLER` + --> $DIR/transmute-size-mismatch.rs:22:36 + | +LL | const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-enum.32bit.stderr b/tests/ui/consts/const-eval/ub-enum.32bit.stderr index 2d86bd88f1c..3ad1ac974c8 100644 --- a/tests/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.32bit.stderr @@ -108,13 +108,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:96:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:98:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!` error: aborting due to 13 previous errors diff --git a/tests/ui/consts/const-eval/ub-enum.64bit.stderr b/tests/ui/consts/const-eval/ub-enum.64bit.stderr index a89d7ec5f6d..a66706d1af9 100644 --- a/tests/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.64bit.stderr @@ -108,13 +108,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:96:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:98:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!` error: aborting due to 13 previous errors diff --git a/tests/ui/consts/const-eval/ub-uninhabit.rs b/tests/ui/consts/const-eval/ub-uninhabit.rs index 4c4ef216d86..10edae437ee 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.rs +++ b/tests/ui/consts/const-eval/ub-uninhabit.rs @@ -14,12 +14,12 @@ union MaybeUninit<T: Copy> { } const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; //~^ ERROR it is undefined behavior to use this value const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed fn main() {} diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr index 0ae376d03fc..733975fc0e9 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.stderr +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,11 +1,8 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:16:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-uninhabit.rs:16:35 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:19:1 @@ -18,14 +15,11 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:22:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-uninhabit.rs:22:42 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index 69fb1a59d4f..74bc6317c80 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/validate_uninhabited_zsts.rs:4:14 | LL | unsafe { std::mem::transmute(()) } - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!` | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 @@ -24,14 +24,11 @@ note: inside `FOO` LL | const FOO: [empty::Empty; 3] = [foo(); 3]; | ^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/validate_uninhabited_zsts.rs:21:1 +error[E0080]: evaluation of constant value failed + --> $DIR/validate_uninhabited_zsts.rs:21:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 0, align: 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type empty::Void warning: the type `empty::Empty` does not permit zero-initialization --> $DIR/validate_uninhabited_zsts.rs:21:42 diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr index 69fb1a59d4f..74bc6317c80 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/validate_uninhabited_zsts.rs:4:14 | LL | unsafe { std::mem::transmute(()) } - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!` | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 @@ -24,14 +24,11 @@ note: inside `FOO` LL | const FOO: [empty::Empty; 3] = [foo(); 3]; | ^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/validate_uninhabited_zsts.rs:21:1 +error[E0080]: evaluation of constant value failed + --> $DIR/validate_uninhabited_zsts.rs:21:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 0, align: 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type empty::Void warning: the type `empty::Empty` does not permit zero-initialization --> $DIR/validate_uninhabited_zsts.rs:21:42 diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs index c0b32621505..b6783175dd3 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs @@ -19,7 +19,7 @@ pub mod empty { const FOO: [empty::Empty; 3] = [foo(); 3]; const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed //~| WARN the type `empty::Empty` does not permit zero-initialization fn main() { diff --git a/tests/ui/consts/issue-64506.rs b/tests/ui/consts/issue-64506.rs index db3e85a7bdf..9275a8a072d 100644 --- a/tests/ui/consts/issue-64506.rs +++ b/tests/ui/consts/issue-64506.rs @@ -1,4 +1,4 @@ -// check-pass +// check-fail #[derive(Copy, Clone)] pub struct ChildStdin { @@ -14,6 +14,7 @@ const FOO: () = { b: (), } let x = unsafe { Foo { b: () }.a }; + //~^ ERROR: evaluation of constant value failed let x = &x.inner; }; diff --git a/tests/ui/consts/issue-64506.stderr b/tests/ui/consts/issue-64506.stderr new file mode 100644 index 00000000000..31a5b1df837 --- /dev/null +++ b/tests/ui/consts/issue-64506.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-64506.rs:16:22 + | +LL | let x = unsafe { Foo { b: () }.a }; + | ^^^^^^^^^^^^^^^ constructing invalid value at .inner: encountered a value of uninhabited type AnonPipe + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/did_you_mean/recursion_limit.stderr b/tests/ui/did_you_mean/recursion_limit.stderr index 247fe4b5b07..70e49566ac0 100644 --- a/tests/ui/did_you_mean/recursion_limit.stderr +++ b/tests/ui/did_you_mean/recursion_limit.stderr @@ -1,15 +1,10 @@ -error[E0275]: overflow evaluating the requirement `K: Send` +error[E0275]: overflow evaluating the requirement `J: Send` --> $DIR/recursion_limit.rs:34:5 | LL | is_send::<A>(); | ^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`) -note: required because it appears within the type `J` - --> $DIR/recursion_limit.rs:24:9 - | -LL | link! { J, K } - | ^ note: required because it appears within the type `I` --> $DIR/recursion_limit.rs:23:9 | diff --git a/tests/ui/error-codes/E0275.stderr b/tests/ui/error-codes/E0275.stderr index cf9a7f69bfb..03c37d6f0e1 100644 --- a/tests/ui/error-codes/E0275.stderr +++ b/tests/ui/error-codes/E0275.stderr @@ -11,7 +11,7 @@ note: required for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar< LL | impl<T> Foo for T where Bar<T>: Foo {} | ^^^ ^ --- unsatisfied trait bound introduced here = note: the full type name has been written to '$TEST_BUILD_DIR/error-codes/E0275/E0275.long-type-hash.txt' - = note: 127 redundant requirements hidden + = note: 126 redundant requirements hidden = note: required for `Bar<T>` to implement `Foo` error: aborting due to previous error diff --git a/tests/ui/feature-gates/feature-gate-link_cfg.stderr b/tests/ui/feature-gates/feature-gate-link_cfg.stderr index 8f47d596521..97b6cbca412 100644 --- a/tests/ui/feature-gates/feature-gate-link_cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-link_cfg.stderr @@ -4,7 +4,6 @@ error[E0658]: link cfg is unstable LL | #[link(name = "foo", cfg(foo))] | ^^^^^^^^ | - = note: see issue #37406 <https://github.com/rust-lang/rust/issues/37406> for more information = help: add `#![feature(link_cfg)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs index 74df300f85a..74f7bc603aa 100644 --- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -1,3 +1,5 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty + #![feature(return_position_impl_trait_in_trait)] pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.current.stderr index d681ecf25e8..05c025cc169 100644 --- a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/box-coerce-span-in-default.rs:3:12 + --> $DIR/box-coerce-span-in-default.rs:5:12 | LL | #![feature(return_position_impl_trait_in_trait)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr new file mode 100644 index 00000000000..05c025cc169 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/box-coerce-span-in-default.rs:5:12 + | +LL | #![feature(return_position_impl_trait_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs index a4d483dee7a..163bb4fcf77 100644 --- a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] //~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.current.stderr index cc3bdf0e571..85450e3b0a0 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.current.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/default-body-type-err-2.rs:8:9 + --> $DIR/default-body-type-err-2.rs:10:9 | LL | 42 | ^^- help: try using a conversion method: `.to_string()` diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr new file mode 100644 index 00000000000..85450e3b0a0 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/default-body-type-err-2.rs:10:9 + | +LL | 42 + | ^^- help: try using a conversion method: `.to_string()` + | | + | expected `String`, found integer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs index 45ae2b8ad3a..62323776310 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs @@ -1,4 +1,6 @@ // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![allow(incomplete_features)] #![feature(async_fn_in_trait)] diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.current.stderr index 4742eb37d3e..c949168a377 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.current.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String` - --> $DIR/default-body-type-err.rs:7:22 + --> $DIR/default-body-type-err.rs:10:22 | LL | fn lol(&self) -> impl Deref<Target = String> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String` diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr new file mode 100644 index 00000000000..c949168a377 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr @@ -0,0 +1,12 @@ +error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String` + --> $DIR/default-body-type-err.rs:10:22 + | +LL | fn lol(&self) -> impl Deref<Target = String> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String` +LL | +LL | &1i32 + | ----- return type was inferred to be `&i32` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs index ac9baf91cae..9bd5b777989 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.rs +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![allow(incomplete_features)] #![feature(return_position_impl_trait_in_trait)] diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr index b5fc9d44d36..3c24eff9ae3 100644 --- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr @@ -1,11 +1,11 @@ error: concrete type differs from previous defining opaque type use - --> $DIR/default-body-with-rpit.rs:11:9 + --> $DIR/default-body-with-rpit.rs:13:9 | LL | "" | ^^ expected `impl Debug`, got `&'static str` | note: previous use here - --> $DIR/default-body-with-rpit.rs:10:39 + --> $DIR/default-body-with-rpit.rs:12:39 | LL | async fn baz(&self) -> impl Debug { | _______________________________________^ @@ -14,7 +14,7 @@ LL | | } | |_____^ error[E0720]: cannot resolve opaque type - --> $DIR/default-body-with-rpit.rs:10:28 + --> $DIR/default-body-with-rpit.rs:12:28 | LL | async fn baz(&self) -> impl Debug { | ^^^^^^^^^^ cannot resolve opaque type diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr new file mode 100644 index 00000000000..3c24eff9ae3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr @@ -0,0 +1,24 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/default-body-with-rpit.rs:13:9 + | +LL | "" + | ^^ expected `impl Debug`, got `&'static str` + | +note: previous use here + --> $DIR/default-body-with-rpit.rs:12:39 + | +LL | async fn baz(&self) -> impl Debug { + | _______________________________________^ +LL | | "" +LL | | } + | |_____^ + +error[E0720]: cannot resolve opaque type + --> $DIR/default-body-with-rpit.rs:12:28 + | +LL | async fn baz(&self) -> impl Debug { + | ^^^^^^^^^^ cannot resolve opaque type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs index 0558d95128f..6bcc7b9ef95 100644 --- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs @@ -1,5 +1,7 @@ // edition:2021 // known-bug: #108304 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/default-body.rs b/tests/ui/impl-trait/in-trait/default-body.rs index b0baf5bb10d..ab6a51c6bcb 100644 --- a/tests/ui/impl-trait/in-trait/default-body.rs +++ b/tests/ui/impl-trait/in-trait/default-body.rs @@ -1,5 +1,7 @@ // check-pass // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs index 75b0ec93984..de82544f293 100644 --- a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs +++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs @@ -13,4 +13,10 @@ trait Trait { fn method(&self) -> impl Trait<Type = impl Sized + '_>; } +trait Trait2 { + type Type; + + fn method(&self) -> impl Trait2<Type = impl Trait2<Type = impl Sized + '_> + '_>; +} + fn main() {} diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.stderr b/tests/ui/impl-trait/in-trait/default-method-constraint.current.stderr index 5e18605aa4c..7bb79911f56 100644 --- a/tests/ui/impl-trait/in-trait/default-method-constraint.stderr +++ b/tests/ui/impl-trait/in-trait/default-method-constraint.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-method-constraint.rs:5:12 + --> $DIR/default-method-constraint.rs:7:12 | LL | #![feature(return_position_impl_trait_in_trait)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr b/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr new file mode 100644 index 00000000000..7bb79911f56 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-method-constraint.rs:7:12 + | +LL | #![feature(return_position_impl_trait_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.rs b/tests/ui/impl-trait/in-trait/default-method-constraint.rs index 8c50cc29586..e85fe3c8626 100644 --- a/tests/ui/impl-trait/in-trait/default-method-constraint.rs +++ b/tests/ui/impl-trait/in-trait/default-method-constraint.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next // This didn't work in the previous default RPITIT method hack attempt diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr index aa5492d285e..653016cf009 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr @@ -1,5 +1,5 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` - --> $DIR/doesnt-satisfy.rs:9:17 + --> $DIR/doesnt-satisfy.rs:12:17 | LL | fn bar() -> () {} | ^^ `()` cannot be formatted with the default formatter @@ -7,7 +7,7 @@ LL | fn bar() -> () {} = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Foo::bar::{opaque#0}` - --> $DIR/doesnt-satisfy.rs:5:22 + --> $DIR/doesnt-satisfy.rs:8:22 | LL | fn bar() -> impl std::fmt::Display; | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::bar::{opaque#0}` diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr new file mode 100644 index 00000000000..bbfa089ceef --- /dev/null +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr @@ -0,0 +1,17 @@ +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/doesnt-satisfy.rs:12:17 + | +LL | fn bar() -> () {} + | ^^ `()` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `Foo::{opaque#0}` + --> $DIR/doesnt-satisfy.rs:8:22 + | +LL | fn bar() -> impl std::fmt::Display; + | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs index bb4e0d44f3e..fcd0b51eea4 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.current.stderr index d7f2e460fb0..b8a793e1a7b 100644 --- a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr +++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/dont-project-to-rpitit-with-no-value.rs:1:12 + --> $DIR/dont-project-to-rpitit-with-no-value.rs:4:12 | LL | #![feature(return_position_impl_trait_in_trait)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(return_position_impl_trait_in_trait)] = note: `#[warn(incomplete_features)]` on by default error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/dont-project-to-rpitit-with-no-value.rs:9:1 + --> $DIR/dont-project-to-rpitit-with-no-value.rs:12:1 | LL | fn foo(&self) -> impl Sized; | ---------------------------- `foo` from trait diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.next.stderr b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.next.stderr new file mode 100644 index 00000000000..b8a793e1a7b --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.next.stderr @@ -0,0 +1,21 @@ +warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/dont-project-to-rpitit-with-no-value.rs:4:12 + | +LL | #![feature(return_position_impl_trait_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/dont-project-to-rpitit-with-no-value.rs:12:1 + | +LL | fn foo(&self) -> impl Sized; + | ---------------------------- `foo` from trait +... +LL | impl MyTrait for i32 { + | ^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs index 746a4a929ae..8329ce1f835 100644 --- a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs +++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] //~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete @@ -7,7 +10,7 @@ trait MyTrait { } impl MyTrait for i32 { -//~^ ERROR not all trait items implemented, missing: `foo` + //~^ ERROR not all trait items implemented, missing: `foo` fn bar(&self) -> impl Sized { self.foo() } diff --git a/tests/ui/impl-trait/in-trait/early.rs b/tests/ui/impl-trait/in-trait/early.rs index 9c1c2b50339..831033a5880 100644 --- a/tests/ui/impl-trait/in-trait/early.rs +++ b/tests/ui/impl-trait/in-trait/early.rs @@ -1,5 +1,7 @@ // check-pass // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr index cd42683e022..310edbcb6cd 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/generics-mismatch.rs:11:12 + --> $DIR/generics-mismatch.rs:14:12 | LL | fn bar(&self) -> impl Sized; | - expected 0 type parameters diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr new file mode 100644 index 00000000000..310edbcb6cd --- /dev/null +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr @@ -0,0 +1,12 @@ +error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/generics-mismatch.rs:14:12 + | +LL | fn bar(&self) -> impl Sized; + | - expected 0 type parameters +... +LL | fn bar<T>(&self) {} + | ^ found 1 type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs index cc0fc720ebb..9259ca193d1 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/issue-102301.rs b/tests/ui/impl-trait/in-trait/issue-102301.rs index a93714a658e..1329ca29d06 100644 --- a/tests/ui/impl-trait/in-trait/issue-102301.rs +++ b/tests/ui/impl-trait/in-trait/issue-102301.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.current.stderr index 87219941d91..cac9a29f644 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102571.current.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-102571.rs:20:9 + --> $DIR/issue-102571.rs:23:9 | LL | let () = t.bar(); | ^^ ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>` diff --git a/tests/ui/impl-trait/in-trait/issue-102571.next.stderr b/tests/ui/impl-trait/in-trait/issue-102571.next.stderr new file mode 100644 index 00000000000..cac9a29f644 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/issue-102571.next.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-102571.rs:23:9 + | +LL | let () = t.bar(); + | ^^ ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>` + | | + | expected associated type, found `()` + | + = note: expected associated type `impl Deref<Target = impl std::fmt::Display + ?Sized>` + found unit type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs index 61c91e64417..f0ddab5e7f2 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.rs +++ b/tests/ui/impl-trait/in-trait/issue-102571.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs index 2e06629699a..f48d9fa26c0 100644 --- a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.current.stderr index dc621d6b8a8..f48e7a1ed14 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr +++ b/tests/ui/impl-trait/in-trait/specialization-broken.current.stderr @@ -1,5 +1,5 @@ error[E0053]: method `bar` has an incompatible type for trait - --> $DIR/specialization-broken.rs:16:22 + --> $DIR/specialization-broken.rs:19:22 | LL | default impl<U> Foo for U | - this type parameter @@ -11,7 +11,7 @@ LL | fn bar(&self) -> U { | help: change the output type to match the trait: `impl Sized` | note: type in trait - --> $DIR/specialization-broken.rs:9:22 + --> $DIR/specialization-broken.rs:12:22 | LL | fn bar(&self) -> impl Sized; | ^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | fn bar(&self) -> impl Sized; found signature `fn(&U) -> U` error: method with return-position `impl Trait` in trait cannot be specialized - --> $DIR/specialization-broken.rs:16:5 + --> $DIR/specialization-broken.rs:19:5 | LL | fn bar(&self) -> U { | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr new file mode 100644 index 00000000000..f48e7a1ed14 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr @@ -0,0 +1,31 @@ +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/specialization-broken.rs:19:22 + | +LL | default impl<U> Foo for U + | - this type parameter +... +LL | fn bar(&self) -> U { + | ^ + | | + | expected associated type, found type parameter `U` + | help: change the output type to match the trait: `impl Sized` + | +note: type in trait + --> $DIR/specialization-broken.rs:12:22 + | +LL | fn bar(&self) -> impl Sized; + | ^^^^^^^^^^ + = note: expected signature `fn(&U) -> impl Sized` + found signature `fn(&U) -> U` + +error: method with return-position `impl Trait` in trait cannot be specialized + --> $DIR/specialization-broken.rs:19:5 + | +LL | fn bar(&self) -> U { + | ^^^^^^^^^^^^^^^^^^ + | + = note: specialization behaves in inconsistent and surprising ways with `#![feature(return_position_impl_trait_in_trait)]`, and for now is disallowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.rs b/tests/ui/impl-trait/in-trait/specialization-broken.rs index 2fcffdf3f9a..658d0709717 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.rs +++ b/tests/ui/impl-trait/in-trait/specialization-broken.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + // FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not. // But we fixed an ICE anyways. diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.current.stderr index 8ff54cad951..64c942705cf 100644 --- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.current.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/trait-more-generics-than-impl.rs:11:11 + --> $DIR/trait-more-generics-than-impl.rs:14:11 | LL | fn bar<T>() -> impl Sized; | - expected 1 type parameter diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr new file mode 100644 index 00000000000..64c942705cf --- /dev/null +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr @@ -0,0 +1,12 @@ +error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter + --> $DIR/trait-more-generics-than-impl.rs:14:11 + | +LL | fn bar<T>() -> impl Sized; + | - expected 1 type parameter +... +LL | fn bar() -> impl Sized {} + | ^ found 0 type parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs index 0bbe50ea6fd..c2e394a1f66 100644 --- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr index 03cc4c2b93b..8392f26e7c8 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:9:22 + --> $DIR/wf-bounds.rs:11:22 | LL | fn nya() -> impl Wf<Vec<[u8]>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -9,14 +9,14 @@ note: required by a bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:12:23 + --> $DIR/wf-bounds.rs:14:23 | LL | fn nya2() -> impl Wf<[u8]>; | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wf` - --> $DIR/wf-bounds.rs:6:10 + --> $DIR/wf-bounds.rs:8:10 | LL | trait Wf<T> {} | ^ required by this bound in `Wf` diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr new file mode 100644 index 00000000000..8392f26e7c8 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr @@ -0,0 +1,30 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/wf-bounds.rs:11:22 + | +LL | fn nya() -> impl Wf<Vec<[u8]>>; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/wf-bounds.rs:14:23 + | +LL | fn nya2() -> impl Wf<[u8]>; + | ^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `Wf` + --> $DIR/wf-bounds.rs:8:10 + | +LL | trait Wf<T> {} + | ^ required by this bound in `Wf` +help: consider relaxing the implicit `Sized` restriction + | +LL | trait Wf<T: ?Sized> {} + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.rs b/tests/ui/impl-trait/in-trait/wf-bounds.rs index 2c71583b312..39f41275315 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.rs +++ b/tests/ui/impl-trait/in-trait/wf-bounds.rs @@ -1,4 +1,6 @@ // issue #101663 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/where-clause.rs b/tests/ui/impl-trait/in-trait/where-clause.rs index 87bac519cf3..88d86e2b541 100644 --- a/tests/ui/impl-trait/in-trait/where-clause.rs +++ b/tests/ui/impl-trait/in-trait/where-clause.rs @@ -1,5 +1,7 @@ // check-pass // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/nested-return-type2.rs b/tests/ui/impl-trait/nested-return-type2.rs index fe883ce6fc8..e1d5511379e 100644 --- a/tests/ui/impl-trait/nested-return-type2.rs +++ b/tests/ui/impl-trait/nested-return-type2.rs @@ -26,7 +26,6 @@ impl<R: Duh, F: FnMut() -> R> Trait for F { // Lazy TAIT would error out, but we inserted a hack to make it work again, // keeping backwards compatibility. fn foo() -> impl Trait<Assoc = impl Send> { - //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds || 42 } diff --git a/tests/ui/impl-trait/nested-return-type2.stderr b/tests/ui/impl-trait/nested-return-type2.stderr deleted file mode 100644 index 09ad3bd05c1..00000000000 --- a/tests/ui/impl-trait/nested-return-type2.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds - --> $DIR/nested-return-type2.rs:28:24 - | -LL | type Assoc: Duh; - | --- this associated type bound is unsatisfied for `impl Send` -... -LL | fn foo() -> impl Trait<Assoc = impl Send> { - | ^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(opaque_hidden_inferred_bound)]` on by default -help: add this bound - | -LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> { - | +++++ - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/nested-return-type3.rs b/tests/ui/impl-trait/nested-return-type3.rs index 5a764fc4c28..74b4dae22eb 100644 --- a/tests/ui/impl-trait/nested-return-type3.rs +++ b/tests/ui/impl-trait/nested-return-type3.rs @@ -13,7 +13,6 @@ impl<F: Duh> Trait for F { } fn foo() -> impl Trait<Assoc = impl Send> { - //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds 42 } diff --git a/tests/ui/impl-trait/nested-return-type3.stderr b/tests/ui/impl-trait/nested-return-type3.stderr deleted file mode 100644 index 632de71aa4c..00000000000 --- a/tests/ui/impl-trait/nested-return-type3.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds - --> $DIR/nested-return-type3.rs:15:24 - | -LL | type Assoc: Duh; - | --- this associated type bound is unsatisfied for `impl Send` -... -LL | fn foo() -> impl Trait<Assoc = impl Send> { - | ^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(opaque_hidden_inferred_bound)]` on by default -help: add this bound - | -LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> { - | +++++ - -warning: 1 warning emitted - diff --git a/tests/ui/implied-bounds/normalization.rs b/tests/ui/implied-bounds/normalization.rs deleted file mode 100644 index f776fc98a9e..00000000000 --- a/tests/ui/implied-bounds/normalization.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Test that we get implied bounds from complex projections after normalization. - -// check-pass - -// implementations wil ensure that -// WF(<T as Combine<'a>>::Ty) implies T: 'a -trait Combine<'a> { - type Ty; -} - -impl<'a, T: 'a> Combine<'a> for Box<T> { - type Ty = &'a T; -} - -// ======= Wrappers ====== - -// normalizes to a projection -struct WrapA<T>(T); -impl<'a, T> Combine<'a> for WrapA<T> -where - T: Combine<'a>, -{ - type Ty = T::Ty; -} - -// <WrapB<T> as Combine<'a>>::Ty normalizes to a type variable ?X -// with constraint `<T as Combine<'a>>::Ty == ?X` -struct WrapB<T>(T); -impl<'a, X, T> Combine<'a> for WrapB<T> -where - T: Combine<'a, Ty = X>, -{ - type Ty = X; -} - -// <WrapC<T> as Combine<'a>>::Ty normalizes to `&'a &'?x ()` -// with constraint `<T as Combine<'a>>::Ty == &'a &'?x ()` -struct WrapC<T>(T); -impl<'a, 'x: 'a, T> Combine<'a> for WrapC<T> -where - T: Combine<'a, Ty = &'a &'x ()>, -{ - type Ty = &'a &'x (); -} - -//==== Test implied bounds ====== - -fn test_wrap<'a, 'b, 'c1, 'c2, A, B>( - _: <WrapA<Box<A>> as Combine<'a>>::Ty, // normalized: &'a A - _: <WrapB<Box<B>> as Combine<'b>>::Ty, // normalized: &'b B - _: <WrapC<Box<&'c1 ()>> as Combine<'c2>>::Ty, // normalized: &'c2 &'c1 () -) { - None::<&'a A>; - None::<&'b B>; - None::<&'c2 &'c1 ()>; -} - -fn main() {} diff --git a/tests/ui/imports/auxiliary/glob-conflict.rs b/tests/ui/imports/auxiliary/glob-conflict.rs index c83db64c643..8a146378b43 100644 --- a/tests/ui/imports/auxiliary/glob-conflict.rs +++ b/tests/ui/imports/auxiliary/glob-conflict.rs @@ -1,3 +1,5 @@ +#![allow(ambiguous_glob_reexports)] + mod m1 { pub fn f() {} } diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.rs b/tests/ui/imports/local-modularized-tricky-fail-1.rs index 29e9b8ec841..ce700ae0de9 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.rs +++ b/tests/ui/imports/local-modularized-tricky-fail-1.rs @@ -1,4 +1,5 @@ #![feature(decl_macro)] +#![allow(ambiguous_glob_reexports)] macro_rules! define_exported { () => { #[macro_export] diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr index 20eadaaaa56..52a01e8bcdf 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr @@ -1,12 +1,12 @@ error[E0659]: `exported` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:28:1 + --> $DIR/local-modularized-tricky-fail-1.rs:29:1 | LL | exported!(); | ^^^^^^^^ ambiguous name | = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution note: `exported` could refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:5:5 + --> $DIR/local-modularized-tricky-fail-1.rs:6:5 | LL | / macro_rules! exported { LL | | () => () @@ -16,7 +16,7 @@ LL | | } LL | define_exported!(); | ------------------ in this macro invocation note: `exported` could also refer to the macro imported here - --> $DIR/local-modularized-tricky-fail-1.rs:22:5 + --> $DIR/local-modularized-tricky-fail-1.rs:23:5 | LL | use inner1::*; | ^^^^^^^^^ @@ -24,7 +24,7 @@ LL | use inner1::*; = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `panic` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:35:5 + --> $DIR/local-modularized-tricky-fail-1.rs:36:5 | LL | panic!(); | ^^^^^ ambiguous name @@ -32,7 +32,7 @@ LL | panic!(); = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution = note: `panic` could refer to a macro from prelude note: `panic` could also refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:11:5 + --> $DIR/local-modularized-tricky-fail-1.rs:12:5 | LL | / macro_rules! panic { LL | | () => () @@ -45,7 +45,7 @@ LL | define_panic!(); = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `include` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:46:1 + --> $DIR/local-modularized-tricky-fail-1.rs:47:1 | LL | include!(); | ^^^^^^^ ambiguous name @@ -53,7 +53,7 @@ LL | include!(); = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution = note: `include` could refer to a macro from prelude note: `include` could also refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:17:5 + --> $DIR/local-modularized-tricky-fail-1.rs:18:5 | LL | / macro_rules! include { LL | | () => () diff --git a/tests/ui/issues/issue-19086.stderr b/tests/ui/issues/issue-19086.stderr index a3c06a72511..90d0bb40655 100644 --- a/tests/ui/issues/issue-19086.stderr +++ b/tests/ui/issues/issue-19086.stderr @@ -5,7 +5,7 @@ LL | FooB { x: i32, y: i32 } | ----------------------- `FooB` defined here ... LL | FooB(a, b) => println!("{} {}", a, b), - | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }` + | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: b }` error: aborting due to previous error diff --git a/tests/ui/issues/issue-20413.stderr b/tests/ui/issues/issue-20413.stderr index 202e8463145..8891a26784e 100644 --- a/tests/ui/issues/issue-20413.stderr +++ b/tests/ui/issues/issue-20413.stderr @@ -20,51 +20,51 @@ note: required for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoDa LL | impl<T> Foo for T where NoData<T>: Foo { | ^^^ ^ --- unsatisfied trait bound introduced here = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' - = note: 127 redundant requirements hidden + = note: 126 redundant requirements hidden = note: required for `NoData<T>` to implement `Foo` -error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>: Baz` +error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>: Bar` --> $DIR/issue-20413.rs:28:42 | LL | impl<T> Bar for T where EvenLessData<T>: Baz { | ^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) -note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar` - --> $DIR/issue-20413.rs:28:9 - | -LL | impl<T> Bar for T where EvenLessData<T>: Baz { - | ^^^ ^ --- unsatisfied trait bound introduced here - = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz` --> $DIR/issue-20413.rs:35:9 | LL | impl<T> Baz for T where AlmostNoData<T>: Bar { | ^^^ ^ --- unsatisfied trait bound introduced here = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' - = note: 126 redundant requirements hidden +note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar` + --> $DIR/issue-20413.rs:28:9 + | +LL | impl<T> Bar for T where EvenLessData<T>: Baz { + | ^^^ ^ --- unsatisfied trait bound introduced here + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' + = note: 125 redundant requirements hidden = note: required for `EvenLessData<T>` to implement `Baz` -error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>: Bar` +error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>: Baz` --> $DIR/issue-20413.rs:35:42 | LL | impl<T> Baz for T where AlmostNoData<T>: Bar { | ^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) -note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz` - --> $DIR/issue-20413.rs:35:9 - | -LL | impl<T> Baz for T where AlmostNoData<T>: Bar { - | ^^^ ^ --- unsatisfied trait bound introduced here - = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar` --> $DIR/issue-20413.rs:28:9 | LL | impl<T> Bar for T where EvenLessData<T>: Baz { | ^^^ ^ --- unsatisfied trait bound introduced here = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' - = note: 126 redundant requirements hidden +note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz` + --> $DIR/issue-20413.rs:35:9 + | +LL | impl<T> Baz for T where AlmostNoData<T>: Bar { + | ^^^ ^ --- unsatisfied trait bound introduced here + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' + = note: 125 redundant requirements hidden = note: required for `AlmostNoData<T>` to implement `Bar` error: aborting due to 4 previous errors diff --git a/tests/ui/late-bound-lifetimes/issue-80618.rs b/tests/ui/late-bound-lifetimes/issue-80618.rs new file mode 100644 index 00000000000..6aa8ff461a9 --- /dev/null +++ b/tests/ui/late-bound-lifetimes/issue-80618.rs @@ -0,0 +1,8 @@ +fn foo<'a>(x: &'a str) -> &'a str { + x +} + +fn main() { + let _ = foo::<'static>; +//~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present [E0794] +} diff --git a/tests/ui/late-bound-lifetimes/issue-80618.stderr b/tests/ui/late-bound-lifetimes/issue-80618.stderr new file mode 100644 index 00000000000..cf7423fc16f --- /dev/null +++ b/tests/ui/late-bound-lifetimes/issue-80618.stderr @@ -0,0 +1,15 @@ +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/issue-80618.rs:6:19 + | +LL | let _ = foo::<'static>; + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/issue-80618.rs:1:8 + | +LL | fn foo<'a>(x: &'a str) -> &'a str { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0794`. diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs index 1c122f42e59..0ae68ad04f7 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.rs +++ b/tests/ui/lifetimes/unusual-rib-combinations.rs @@ -25,4 +25,9 @@ fn d<const C: S>() {} //~^ ERROR missing lifetime specifier //~| ERROR `S<'_>` is forbidden as the type of a const generic parameter +trait Foo<'a> {} +struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; +//~^ ERROR use of non-static lifetime `'a` in const generic +//~| ERROR `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter + fn main() {} diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 68f4fce0178..20163d289b1 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -9,6 +9,14 @@ help: consider introducing a named lifetime parameter LL | fn d<'a, const C: S<'a>>() {} | +++ ++++ +error[E0771]: use of non-static lifetime `'a` in const generic + --> $DIR/unusual-rib-combinations.rs:29:22 + | +LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; + | ^^ + | + = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052> + error[E0214]: parenthesized type parameters may only be used with a `Fn` trait --> $DIR/unusual-rib-combinations.rs:7:16 | @@ -55,7 +63,16 @@ LL | fn d<const C: S>() {} = note: the only supported types are integers, `bool` and `char` = help: more complex types are supported with `#![feature(adt_const_params)]` -error: aborting due to 7 previous errors +error: `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter + --> $DIR/unusual-rib-combinations.rs:29:21 + | +LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = help: more complex types are supported with `#![feature(adt_const_params)]` + +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0106, E0214, E0308. +Some errors have detailed explanations: E0106, E0214, E0308, E0771. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/linkage-attr/issue-109144.rs b/tests/ui/linkage-attr/issue-109144.rs new file mode 100644 index 00000000000..2f740e55389 --- /dev/null +++ b/tests/ui/linkage-attr/issue-109144.rs @@ -0,0 +1,4 @@ +#![crate_type = "lib"] +#[link(kind = "static", modifiers = "+whole-archive,+bundle")] +//~^ ERROR `#[link]` attribute requires a `name = "string"` argument +extern {} diff --git a/tests/ui/linkage-attr/issue-109144.stderr b/tests/ui/linkage-attr/issue-109144.stderr new file mode 100644 index 00000000000..33187cfdbb6 --- /dev/null +++ b/tests/ui/linkage-attr/issue-109144.stderr @@ -0,0 +1,9 @@ +error[E0459]: `#[link]` attribute requires a `name = "string"` argument + --> $DIR/issue-109144.rs:2:1 + | +LL | #[link(kind = "static", modifiers = "+whole-archive,+bundle")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `name` argument + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0459`. diff --git a/tests/ui/lint/anonymous-reexport.rs b/tests/ui/lint/anonymous-reexport.rs new file mode 100644 index 00000000000..11ac5d07140 --- /dev/null +++ b/tests/ui/lint/anonymous-reexport.rs @@ -0,0 +1,19 @@ +#![deny(unused_imports)] +#![crate_type = "rlib"] + +mod my_mod { + pub trait Foo {} + pub type TyFoo = dyn Foo; + pub struct Bar; + pub type TyBar = Bar; +} + +pub use self::my_mod::Foo as _; +pub use self::my_mod::TyFoo as _; //~ ERROR unused import +pub use self::my_mod::Bar as _; //~ ERROR unused import +pub use self::my_mod::TyBar as _; //~ ERROR unused import +pub use self::my_mod::{Bar as _}; //~ ERROR unused import +pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR unused import +pub use self::my_mod::{Bar as _, TyBar as _}; //~ ERROR unused imports +#[allow(unused_imports)] +use self::my_mod::TyBar as _; diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr new file mode 100644 index 00000000000..e3854a5459e --- /dev/null +++ b/tests/ui/lint/anonymous-reexport.stderr @@ -0,0 +1,44 @@ +error: unused import: `self::my_mod::TyFoo as _` + --> $DIR/anonymous-reexport.rs:12:9 + | +LL | pub use self::my_mod::TyFoo as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/anonymous-reexport.rs:1:9 + | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: unused import: `self::my_mod::Bar as _` + --> $DIR/anonymous-reexport.rs:13:9 + | +LL | pub use self::my_mod::Bar as _; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unused import: `self::my_mod::TyBar as _` + --> $DIR/anonymous-reexport.rs:14:9 + | +LL | pub use self::my_mod::TyBar as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unused import: `Bar as _` + --> $DIR/anonymous-reexport.rs:15:24 + | +LL | pub use self::my_mod::{Bar as _}; + | ^^^^^^^^ + +error: unused import: `Bar as _` + --> $DIR/anonymous-reexport.rs:16:24 + | +LL | pub use self::my_mod::{Bar as _, Foo as _}; + | ^^^^^^^^ + +error: unused imports: `Bar as _`, `TyBar as _` + --> $DIR/anonymous-reexport.rs:17:24 + | +LL | pub use self::my_mod::{Bar as _, TyBar as _}; + | ^^^^^^^^ ^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 809e0602671..09fda33dbec 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -122,8 +122,8 @@ mod banana { weight: u32, length: u16, } // note: distinct type - // This should not trigger the lint because two::Banana is structurally equivalent to - // one::Banana. + // This should not trigger the lint because two::Banana is structurally equivalent to + // one::Banana. extern "C" { fn weigh_banana(count: *const Banana) -> u64; } @@ -223,6 +223,27 @@ mod transparent { } } +#[allow(improper_ctypes)] +mod zst { + mod transparent { + #[repr(transparent)] + struct TransparentZst(()); + extern "C" { + fn zst() -> (); + fn transparent_zst() -> TransparentZst; + } + } + + mod not_transparent { + struct NotTransparentZst(()); + extern "C" { + // These shouldn't warn since all return types are zero sized + fn zst() -> NotTransparentZst; + fn transparent_zst() -> NotTransparentZst; + } + } +} + mod missing_return_type { mod a { extern "C" { @@ -397,10 +418,14 @@ mod hidden_niche { use std::num::NonZeroUsize; #[repr(transparent)] - struct Transparent { x: NonZeroUsize } + struct Transparent { + x: NonZeroUsize, + } #[repr(transparent)] - struct TransparentNoNiche { y: UnsafeCell<NonZeroUsize> } + struct TransparentNoNiche { + y: UnsafeCell<NonZeroUsize>, + } extern "C" { fn hidden_niche_transparent() -> Option<Transparent>; diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 217eed6c92c..5d457ba0ec7 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -130,7 +130,7 @@ LL | fn transparent_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:238:13 + --> $DIR/clashing-extern-fn.rs:259:13 | LL | fn missing_return_type() -> usize; | ---------------------------------- `missing_return_type` previously declared here @@ -142,7 +142,7 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:256:13 + --> $DIR/clashing-extern-fn.rs:277:13 | LL | fn non_zero_usize() -> core::num::NonZeroUsize; | ----------------------------------------------- `non_zero_usize` previously declared here @@ -154,7 +154,7 @@ LL | fn non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:258:13 + --> $DIR/clashing-extern-fn.rs:279:13 | LL | fn non_null_ptr() -> core::ptr::NonNull<usize>; | ----------------------------------------------- `non_null_ptr` previously declared here @@ -166,7 +166,7 @@ LL | fn non_null_ptr() -> *const usize; found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:356:13 + --> $DIR/clashing-extern-fn.rs:377:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -178,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:358:13 + --> $DIR/clashing-extern-fn.rs:379:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here @@ -190,7 +190,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; found `unsafe extern "C" fn() -> *const isize` warning: `hidden_niche_transparent_no_niche` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:408:13 + --> $DIR/clashing-extern-fn.rs:433:13 | LL | fn hidden_niche_transparent_no_niche() -> usize; | ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here @@ -202,7 +202,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN found `unsafe extern "C" fn() -> Option<TransparentNoNiche>` warning: `hidden_niche_unsafe_cell` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:412:13 + --> $DIR/clashing-extern-fn.rs:437:13 | LL | fn hidden_niche_unsafe_cell() -> usize; | --------------------------------------- `hidden_niche_unsafe_cell` previously declared here @@ -214,7 +214,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>` warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:408:55 + --> $DIR/clashing-extern-fn.rs:433:55 | LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -224,7 +224,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN = note: `#[warn(improper_ctypes)]` on by default warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:412:46 + --> $DIR/clashing-extern-fn.rs:437:46 | LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe diff --git a/tests/ui/lint/fn_must_use.stderr b/tests/ui/lint/fn_must_use.stderr index 657f23c6085..e88c1a9b8a9 100644 --- a/tests/ui/lint/fn_must_use.stderr +++ b/tests/ui/lint/fn_must_use.stderr @@ -10,12 +10,21 @@ note: the lint level is defined here | LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = need_to_use_this_value(); + | +++++++ warning: unused return value of `MyStruct::need_to_use_this_method_value` that must be used --> $DIR/fn_must_use.rs:60:5 | LL | m.need_to_use_this_method_value(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = m.need_to_use_this_method_value(); + | +++++++ warning: unused return value of `EvenNature::is_even` that must be used --> $DIR/fn_must_use.rs:61:5 @@ -24,24 +33,43 @@ LL | m.is_even(); // trait method! | ^^^^^^^^^^^ | = note: no side effects +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = m.is_even(); // trait method! + | +++++++ warning: unused return value of `MyStruct::need_to_use_this_associated_function_value` that must be used --> $DIR/fn_must_use.rs:64:5 | LL | MyStruct::need_to_use_this_associated_function_value(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = MyStruct::need_to_use_this_associated_function_value(); + | +++++++ warning: unused return value of `std::cmp::PartialEq::eq` that must be used --> $DIR/fn_must_use.rs:70:5 | LL | 2.eq(&3); | ^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = 2.eq(&3); + | +++++++ warning: unused return value of `std::cmp::PartialEq::eq` that must be used --> $DIR/fn_must_use.rs:71:5 | LL | m.eq(&n); | ^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = m.eq(&n); + | +++++++ warning: unused comparison that must be used --> $DIR/fn_must_use.rs:74:5 diff --git a/tests/ui/lint/unused/must-use-box-from-raw.stderr b/tests/ui/lint/unused/must-use-box-from-raw.stderr index 47ab613bec2..4898db7fe3d 100644 --- a/tests/ui/lint/unused/must-use-box-from-raw.stderr +++ b/tests/ui/lint/unused/must-use-box-from-raw.stderr @@ -10,6 +10,10 @@ note: the lint level is defined here | LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Box::from_raw(ptr); + | +++++++ warning: 1 warning emitted diff --git a/tests/ui/lint/unused/must_use-unit.stderr b/tests/ui/lint/unused/must_use-unit.stderr index 9fcbc5074ea..993a19e5f04 100644 --- a/tests/ui/lint/unused/must_use-unit.stderr +++ b/tests/ui/lint/unused/must_use-unit.stderr @@ -9,12 +9,21 @@ note: the lint level is defined here | LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo(); + | +++++++ error: unused return value of `bar` that must be used --> $DIR/must_use-unit.rs:15:5 | LL | bar(); | ^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = bar(); + | +++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unused/unused-async.stderr b/tests/ui/lint/unused/unused-async.stderr index 4bcb26dc165..1c3702ba265 100644 --- a/tests/ui/lint/unused/unused-async.stderr +++ b/tests/ui/lint/unused/unused-async.stderr @@ -16,12 +16,22 @@ error: unused return value of `foo` that must be used | LL | foo(); | ^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo(); + | +++++++ error: unused output of future returned by `foo` that must be used --> $DIR/unused-async.rs:33:5 | LL | foo().await; | ^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo().await; + | +++++++ error: unused implementer of `Future` that must be used --> $DIR/unused-async.rs:34:5 @@ -36,12 +46,22 @@ error: unused return value of `bar` that must be used | LL | bar(); | ^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = bar(); + | +++++++ error: unused output of future returned by `bar` that must be used --> $DIR/unused-async.rs:36:5 | LL | bar().await; | ^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = bar().await; + | +++++++ error: unused implementer of `Future` that must be used --> $DIR/unused-async.rs:37:5 diff --git a/tests/ui/lint/unused/unused-result.stderr b/tests/ui/lint/unused/unused-result.stderr index 4e1ba1fd959..f42995a65d1 100644 --- a/tests/ui/lint/unused/unused-result.stderr +++ b/tests/ui/lint/unused/unused-result.stderr @@ -9,6 +9,10 @@ note: the lint level is defined here | LL | #![deny(unused_results, unused_must_use)] | ^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo::<MustUse>(); + | +++++++ error: unused `MustUseMsg` that must be used --> $DIR/unused-result.rs:22:5 @@ -17,6 +21,10 @@ LL | foo::<MustUseMsg>(); | ^^^^^^^^^^^^^^^^^^^ | = note: some message +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo::<MustUseMsg>(); + | +++++++ error: unused result of type `isize` --> $DIR/unused-result.rs:34:5 @@ -35,6 +43,11 @@ error: unused `MustUse` that must be used | LL | foo::<MustUse>(); | ^^^^^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo::<MustUse>(); + | +++++++ error: unused `MustUseMsg` that must be used --> $DIR/unused-result.rs:36:5 @@ -43,6 +56,10 @@ LL | foo::<MustUseMsg>(); | ^^^^^^^^^^^^^^^^^^^ | = note: some message +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo::<MustUseMsg>(); + | +++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 0f699429e02..9633767c442 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -146,42 +146,76 @@ note: the lint level is defined here | LL | #![deny(unused_attributes, unused_must_use)] | ^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = X; + | +++++++ error: unused `Y` that must be used --> $DIR/unused_attributes-must_use.rs:104:5 | LL | Y::Z; | ^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Y::Z; + | +++++++ error: unused `U` that must be used --> $DIR/unused_attributes-must_use.rs:105:5 | LL | U { unit: () }; | ^^^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = U { unit: () }; + | +++++++ error: unused return value of `U::method` that must be used --> $DIR/unused_attributes-must_use.rs:106:5 | LL | U::method(); | ^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = U::method(); + | +++++++ error: unused return value of `foo` that must be used --> $DIR/unused_attributes-must_use.rs:107:5 | LL | foo(); | ^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo(); + | +++++++ error: unused return value of `foreign_foo` that must be used --> $DIR/unused_attributes-must_use.rs:110:9 | LL | foreign_foo(); | ^^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foreign_foo(); + | +++++++ error: unused return value of `Use::get_four` that must be used --> $DIR/unused_attributes-must_use.rs:118:5 | LL | ().get_four(); | ^^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = ().get_four(); + | +++++++ error: aborting due to 28 previous errors diff --git a/tests/ui/macros/issue-109237.rs b/tests/ui/macros/issue-109237.rs new file mode 100644 index 00000000000..86a193c9e44 --- /dev/null +++ b/tests/ui/macros/issue-109237.rs @@ -0,0 +1,7 @@ +macro_rules! statement { + () => {;}; //~ ERROR expected expression +} + +fn main() { + let _ = statement!(); +} diff --git a/tests/ui/macros/issue-109237.stderr b/tests/ui/macros/issue-109237.stderr new file mode 100644 index 00000000000..d125cff63ea --- /dev/null +++ b/tests/ui/macros/issue-109237.stderr @@ -0,0 +1,18 @@ +error: expected expression, found `;` + --> $DIR/issue-109237.rs:2:12 + | +LL | () => {;}; + | ^ expected expression +... +LL | let _ = statement!(); + | ------------ in this macro invocation + | + = note: the macro call doesn't expand to an expression, but it can expand to a statement + = note: this error originates in the macro `statement` (in Nightly builds, run with -Z macro-backtrace for more info) +help: surround the macro invocation with `{}` to interpret the expansion as a statement + | +LL | let _ = { statement!(); }; + | ~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + diff --git a/tests/ui/macros/nested-use-as.rs b/tests/ui/macros/nested-use-as.rs new file mode 100644 index 00000000000..21aa81e8092 --- /dev/null +++ b/tests/ui/macros/nested-use-as.rs @@ -0,0 +1,83 @@ +// check-pass +// edition:2018 +// issue: https://github.com/rust-lang/rust/issues/97534 + +macro_rules! m { + () => { + macro_rules! foo { + () => {} + } + use foo as bar; + } +} + +m!{} + +use bar as baz; + +baz!{} + +macro_rules! foo2 { + () => {}; +} + +macro_rules! m2 { + () => { + use foo2 as bar2; + }; +} + +m2! {} + +use bar2 as baz2; + +baz2! {} + +macro_rules! n1 { + () => { + macro_rules! n2 { + () => { + macro_rules! n3 { + () => { + macro_rules! n4 { + () => {} + } + use n4 as c4; + } + } + use n3 as c3; + } + } + use n2 as c2; + } +} + +use n1 as c1; +c1!{} +use c2 as a2; +a2!{} +use c3 as a3; +a3!{} +use c4 as a4; +a4!{} + +// https://github.com/rust-lang/rust/pull/108729#issuecomment-1474750675 +// reversed +use d5 as d6; +use d4 as d5; +use d3 as d4; +use d2 as d3; +use d1 as d2; +use foo2 as d1; +d6! {} + +// mess +use f3 as f4; +f5! {} +use f1 as f2; +use f4 as f5; +use f2 as f3; +use foo2 as f1; + +fn main() { +} diff --git a/tests/ui/methods/method-call-lifetime-args-fail.stderr b/tests/ui/methods/method-call-lifetime-args-fail.stderr index 34526256f99..645d8b8d14a 100644 --- a/tests/ui/methods/method-call-lifetime-args-fail.stderr +++ b/tests/ui/methods/method-call-lifetime-args-fail.stderr @@ -30,7 +30,7 @@ note: method defined here, with 2 lifetime parameters: `'a`, `'b` LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } | ^^^^^ -- -- -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:27:15 | LL | S::late::<'static>(S, &0, &0); @@ -42,7 +42,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:29:15 | LL | S::late::<'static, 'static>(S, &0, &0); @@ -54,7 +54,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:31:15 | LL | S::late::<'static, 'static, 'static>(S, &0, &0); @@ -66,7 +66,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:34:21 | LL | S::late_early::<'static, 'static>(S, &0); @@ -78,7 +78,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:36:21 | LL | S::late_early::<'static, 'static, 'static>(S, &0); @@ -90,7 +90,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:40:24 | LL | S::late_implicit::<'static>(S, &0, &0); @@ -102,7 +102,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:42:24 | LL | S::late_implicit::<'static, 'static>(S, &0, &0); @@ -114,7 +114,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:44:24 | LL | S::late_implicit::<'static, 'static, 'static>(S, &0, &0); @@ -126,7 +126,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:47:30 | LL | S::late_implicit_early::<'static, 'static>(S, &0); @@ -138,7 +138,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:49:30 | LL | S::late_implicit_early::<'static, 'static, 'static>(S, &0); @@ -150,7 +150,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:52:35 | LL | S::late_implicit_self_early::<'static, 'static>(&S); @@ -162,7 +162,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:54:35 | LL | S::late_implicit_self_early::<'static, 'static, 'static>(&S); @@ -174,7 +174,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:57:28 | LL | S::late_unused_early::<'static, 'static>(S); @@ -186,7 +186,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:59:28 | LL | S::late_unused_early::<'static, 'static, 'static>(S); @@ -232,4 +232,5 @@ LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } error: aborting due to 18 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0794. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/methods/method-call-lifetime-args.stderr b/tests/ui/methods/method-call-lifetime-args.stderr index 64ae79e9bb2..b215d583217 100644 --- a/tests/ui/methods/method-call-lifetime-args.stderr +++ b/tests/ui/methods/method-call-lifetime-args.stderr @@ -1,4 +1,4 @@ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args.rs:9:15 | LL | S::late::<'static>(S, &0, &0); @@ -10,7 +10,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args.rs:11:24 | LL | S::late_implicit::<'static>(S, &0, &0); @@ -24,3 +24,4 @@ LL | fn late_implicit(self, _: &u8, _: &u8) {} error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0794`. diff --git a/tests/ui/panic-runtime/unwind-tables-target-required.rs b/tests/ui/panic-runtime/unwind-tables-target-required.rs index 3abb52b675a..5a90b314a6e 100644 --- a/tests/ui/panic-runtime/unwind-tables-target-required.rs +++ b/tests/ui/panic-runtime/unwind-tables-target-required.rs @@ -1,10 +1,11 @@ // Tests that the compiler errors if the user tries to turn off unwind tables // when they are required. // -// only-x86_64-windows-msvc +// only-x86_64-pc-windows-msvc // compile-flags: -C force-unwind-tables=no // -// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`. +// dont-check-compiler-stderr +// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no` pub fn main() { } diff --git a/tests/ui/parser/ident-recovery.rs b/tests/ui/parser/ident-recovery.rs new file mode 100644 index 00000000000..7575372b940 --- /dev/null +++ b/tests/ui/parser/ident-recovery.rs @@ -0,0 +1,16 @@ +fn ,comma() { + //~^ ERROR expected identifier, found `,` + struct Foo { + x: i32,, + //~^ ERROR expected identifier, found `,` + y: u32, + } +} + +fn break() { +//~^ ERROR expected identifier, found keyword `break` + let continue = 5; + //~^ ERROR expected identifier, found keyword `continue` +} + +fn main() {} diff --git a/tests/ui/parser/ident-recovery.stderr b/tests/ui/parser/ident-recovery.stderr new file mode 100644 index 00000000000..e9a55026d12 --- /dev/null +++ b/tests/ui/parser/ident-recovery.stderr @@ -0,0 +1,42 @@ +error: expected identifier, found `,` + --> $DIR/ident-recovery.rs:1:4 + | +LL | fn ,comma() { + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected identifier, found `,` + --> $DIR/ident-recovery.rs:4:16 + | +LL | x: i32,, + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected identifier, found keyword `break` + --> $DIR/ident-recovery.rs:10:4 + | +LL | fn break() { + | ^^^^^ expected identifier, found keyword + | +help: escape `break` to use it as an identifier + | +LL | fn r#break() { + | ++ + +error: expected identifier, found keyword `continue` + --> $DIR/ident-recovery.rs:12:9 + | +LL | let continue = 5; + | ^^^^^^^^ expected identifier, found keyword + | +help: escape `continue` to use it as an identifier + | +LL | let r#continue = 5; + | ++ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/integer-literal-start-ident.stderr b/tests/ui/parser/integer-literal-start-ident.stderr index 51c37a0d24c..b2c66129656 100644 --- a/tests/ui/parser/integer-literal-start-ident.stderr +++ b/tests/ui/parser/integer-literal-start-ident.stderr @@ -4,7 +4,11 @@ error: expected identifier, found `1main` LL | fn 1main() {} | ^^^^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/integer-literal-start-ident.rs:1:4 + | +LL | fn 1main() {} + | ^ error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-104088.rs b/tests/ui/parser/issues/issue-104088.rs index 86988c8cd21..3dc636b6a33 100644 --- a/tests/ui/parser/issues/issue-104088.rs +++ b/tests/ui/parser/issues/issue-104088.rs @@ -1,26 +1,19 @@ -fn test() { +fn 1234test() { +//~^ ERROR expected identifier, found `1234test` if let 123 = 123 { println!("yes"); } -} - -fn test_2() { - let 1x = 123; - //~^ ERROR expected identifier, found `1x` -} - -fn test_3() { - let 2x: i32 = 123; - //~^ ERROR expected identifier, found `2x` -} -fn test_4() { if let 2e1 = 123 { //~^ ERROR mismatched types } -} -fn test_5() { let 23name = 123; //~^ ERROR expected identifier, found `23name` + + let 2x: i32 = 123; + //~^ ERROR expected identifier, found `2x` + + let 1x = 123; + //~^ ERROR expected identifier, found `1x` } fn main() {} diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/issues/issue-104088.stderr index 6511a313149..8b751759d69 100644 --- a/tests/ui/parser/issues/issue-104088.stderr +++ b/tests/ui/parser/issues/issue-104088.stderr @@ -1,35 +1,59 @@ -error: expected identifier, found `1x` - --> $DIR/issue-104088.rs:6:9 +error: expected identifier, found `1234test` + --> $DIR/issue-104088.rs:1:4 | -LL | let 1x = 123; - | ^^ expected identifier +LL | fn 1234test() { + | ^^^^^^^^ expected identifier + | +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:1:4 + | +LL | fn 1234test() { + | ^^^^ + +error: expected identifier, found `23name` + --> $DIR/issue-104088.rs:9:9 + | +LL | let 23name = 123; + | ^^^^^^ expected identifier + | +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:9:9 | - = help: identifiers cannot start with a number +LL | let 23name = 123; + | ^^ error: expected identifier, found `2x` - --> $DIR/issue-104088.rs:11:9 + --> $DIR/issue-104088.rs:12:9 | LL | let 2x: i32 = 123; | ^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:12:9 + | +LL | let 2x: i32 = 123; + | ^ -error: expected identifier, found `23name` - --> $DIR/issue-104088.rs:22:9 +error: expected identifier, found `1x` + --> $DIR/issue-104088.rs:15:9 | -LL | let 23name = 123; - | ^^^^^^ expected identifier +LL | let 1x = 123; + | ^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:15:9 + | +LL | let 1x = 123; + | ^ error[E0308]: mismatched types - --> $DIR/issue-104088.rs:16:12 + --> $DIR/issue-104088.rs:5:12 | LL | if let 2e1 = 123 { | ^^^ --- this expression has type `{integer}` | | | expected integer, found floating-point number -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/issue-106862.fixed b/tests/ui/pattern/issue-106862.fixed new file mode 100644 index 00000000000..9b27a61ffd0 --- /dev/null +++ b/tests/ui/pattern/issue-106862.fixed @@ -0,0 +1,44 @@ +// run-rustfix + +#![allow(unused)] + +use Foo::{FooB, FooA}; + +enum Foo { + FooA { opt_x: Option<i32>, y: i32 }, + FooB { x: i32, y: i32 } +} + +fn main() { + let f = FooB { x: 3, y: 4 }; + + match f { + FooB { x: a, y: b } => println!("{} {}", a, b), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooB` + _ => (), + } + + match f { + FooB { x, y } => println!("{} {}", x, y), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooB` + _ => (), + } + + match f { + FooA { opt_x: Some(x), y } => println!("{} {}", x, y), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooA` + _ => (), + } + + match f { + FooB { x: a, y: _ } => println!("{}", a), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooB` + _ => (), + } + + match f { + FooB { x, y } => (), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooB` + _ => (), + } +} diff --git a/tests/ui/pattern/issue-106862.rs b/tests/ui/pattern/issue-106862.rs new file mode 100644 index 00000000000..590430a7843 --- /dev/null +++ b/tests/ui/pattern/issue-106862.rs @@ -0,0 +1,44 @@ +// run-rustfix + +#![allow(unused)] + +use Foo::{FooB, FooA}; + +enum Foo { + FooA { opt_x: Option<i32>, y: i32 }, + FooB { x: i32, y: i32 } +} + +fn main() { + let f = FooB { x: 3, y: 4 }; + + match f { + FooB(a, b) => println!("{} {}", a, b), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooB` + _ => (), + } + + match f { + FooB(x, y) => println!("{} {}", x, y), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooB` + _ => (), + } + + match f { + FooA(Some(x), y) => println!("{} {}", x, y), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooA` + _ => (), + } + + match f { + FooB(a, _, _) => println!("{}", a), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooB` + _ => (), + } + + match f { + FooB() => (), + //~^ ERROR expected tuple struct or tuple variant, found variant `FooB` + _ => (), + } +} diff --git a/tests/ui/pattern/issue-106862.stderr b/tests/ui/pattern/issue-106862.stderr new file mode 100644 index 00000000000..27f8ac97284 --- /dev/null +++ b/tests/ui/pattern/issue-106862.stderr @@ -0,0 +1,48 @@ +error[E0532]: expected tuple struct or tuple variant, found variant `FooB` + --> $DIR/issue-106862.rs:16:9 + | +LL | FooB { x: i32, y: i32 } + | ----------------------- `FooB` defined here +... +LL | FooB(a, b) => println!("{} {}", a, b), + | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: b }` + +error[E0532]: expected tuple struct or tuple variant, found variant `FooB` + --> $DIR/issue-106862.rs:22:9 + | +LL | FooB { x: i32, y: i32 } + | ----------------------- `FooB` defined here +... +LL | FooB(x, y) => println!("{} {}", x, y), + | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }` + +error[E0532]: expected tuple struct or tuple variant, found variant `FooA` + --> $DIR/issue-106862.rs:28:9 + | +LL | FooA { opt_x: Option<i32>, y: i32 }, + | ----------------------------------- `FooA` defined here +... +LL | FooA(Some(x), y) => println!("{} {}", x, y), + | ^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FooA { opt_x: Some(x), y }` + +error[E0532]: expected tuple struct or tuple variant, found variant `FooB` + --> $DIR/issue-106862.rs:34:9 + | +LL | FooB { x: i32, y: i32 } + | ----------------------- `FooB` defined here +... +LL | FooB(a, _, _) => println!("{}", a), + | ^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: _ }` + +error[E0532]: expected tuple struct or tuple variant, found variant `FooB` + --> $DIR/issue-106862.rs:40:9 + | +LL | FooB { x: i32, y: i32 } + | ----------------------- `FooB` defined here +... +LL | FooB() => (), + | ^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0532`. diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs new file mode 100644 index 00000000000..431213e25e4 --- /dev/null +++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs @@ -0,0 +1,33 @@ +#![deny(ambiguous_glob_reexports)] + +pub mod foo { + pub type X = u8; +} + +pub mod bar { + pub type X = u8; + pub type Y = u8; +} + +pub use foo::*; +//~^ ERROR ambiguous glob re-exports +pub use bar::*; + +mod ambiguous { + mod m1 { pub type A = u8; } + mod m2 { pub type A = u8; } + pub use self::m1::*; + //~^ ERROR ambiguous glob re-exports + pub use self::m2::*; +} + +pub mod single { + pub use ambiguous::A; + //~^ ERROR `A` is ambiguous +} + +pub mod glob { + pub use ambiguous::*; +} + +pub fn main() {} diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr new file mode 100644 index 00000000000..07e61dd8643 --- /dev/null +++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr @@ -0,0 +1,47 @@ +error[E0659]: `A` is ambiguous + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:25:24 + | +LL | pub use ambiguous::A; + | ^ ambiguous name + | + = note: ambiguous because of multiple glob imports of a name in the same module +note: `A` could refer to the type alias imported here + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13 + | +LL | pub use self::m1::*; + | ^^^^^^^^^^^ + = help: consider adding an explicit import of `A` to disambiguate +note: `A` could also refer to the type alias imported here + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:21:13 + | +LL | pub use self::m2::*; + | ^^^^^^^^^^^ + = help: consider adding an explicit import of `A` to disambiguate + +error: ambiguous glob re-exports + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:12:9 + | +LL | pub use foo::*; + | ^^^^^^ the name `X` in the type namespace is first re-exported here +LL | +LL | pub use bar::*; + | ------ but the name `X` in the type namespace is also re-exported here + | +note: the lint level is defined here + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:1:9 + | +LL | #![deny(ambiguous_glob_reexports)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ambiguous glob re-exports + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13 + | +LL | pub use self::m1::*; + | ^^^^^^^^^^^ the name `A` in the type namespace is first re-exported here +LL | +LL | pub use self::m2::*; + | ----------- but the name `A` in the type namespace is also re-exported here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs index 87e52881c15..23d2a4b0a99 100644 --- a/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs +++ b/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs @@ -1,5 +1,6 @@ // run-pass // revisions: default mir-opt +//[default] compile-flags: -Zinline-mir=no //[mir-opt] compile-flags: -Zmir-opt-level=4 macro_rules! caller_location_from_macro { @@ -9,13 +10,13 @@ macro_rules! caller_location_from_macro { fn main() { let loc = core::panic::Location::caller(); assert_eq!(loc.file(), file!()); - assert_eq!(loc.line(), 10); + assert_eq!(loc.line(), 11); assert_eq!(loc.column(), 15); // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, // i.e. point to where the macro was invoked, instead of the macro itself. let loc2 = caller_location_from_macro!(); assert_eq!(loc2.file(), file!()); - assert_eq!(loc2.line(), 17); + assert_eq!(loc2.line(), 18); assert_eq!(loc2.column(), 16); } diff --git a/tests/ui/rfc-2091-track-caller/mir-inlined-macro.rs b/tests/ui/rfc-2091-track-caller/mir-inlined-macro.rs new file mode 100644 index 00000000000..a2e8eb27ede --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/mir-inlined-macro.rs @@ -0,0 +1,23 @@ +// run-pass +// revisions: default mir-opt +//[default] compile-flags: -Zinline-mir=no +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +use std::panic::Location; + +macro_rules! f { + () => { + Location::caller() + }; +} + +#[inline(always)] +fn g() -> &'static Location<'static> { + f!() +} + +fn main() { + let loc = g(); + assert_eq!(loc.line(), 16); + assert_eq!(loc.column(), 5); +} diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs index 582b480aa25..5fd7c647c25 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs @@ -2,11 +2,11 @@ // An impl that has an erroneous const substitution should not specialize one // that is well-formed. - +#[derive(Clone)] struct S<const L: usize>; impl<const N: i32> Copy for S<N> {} +//~^ ERROR the constant `N` is not of type `usize` impl<const M: usize> Copy for S<M> {} -//~^ ERROR conflicting implementations of trait `Copy` for type `S<_>` fn main() {} diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index a3906a9a22f..83f311efd39 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -1,11 +1,14 @@ -error[E0119]: conflicting implementations of trait `Copy` for type `S<_>` - --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1 +error: the constant `N` is not of type `usize` + --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29 | LL | impl<const N: i32> Copy for S<N> {} - | -------------------------------- first implementation here -LL | impl<const M: usize> Copy for S<M> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>` + | ^^^^ expected `usize`, found `i32` + | +note: required by a bound in `S` + --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10 + | +LL | struct S<const L: usize>; + | ^^^^^^^^^^^^^^ required by this bound in `S` error: aborting due to previous error -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs b/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs new file mode 100644 index 00000000000..8804186ee1a --- /dev/null +++ b/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs @@ -0,0 +1,13 @@ +#![feature(staged_api)] +#![stable(feature = "libfoo", since = "1.0.0")] + +#[unstable(feature = "foo", reason = "...", issue = "none")] +pub fn foo() {} + +#[stable(feature = "libfoo", since = "1.0.0")] +pub struct Foo; + +impl Foo { + #[unstable(feature = "foo", reason = "...", issue = "none")] + pub fn foo(&self) {} +} diff --git a/tests/ui/stability-attribute/issue-109177.rs b/tests/ui/stability-attribute/issue-109177.rs new file mode 100644 index 00000000000..6d052779c6d --- /dev/null +++ b/tests/ui/stability-attribute/issue-109177.rs @@ -0,0 +1,13 @@ +// aux-build: similar-unstable-method.rs + +extern crate similar_unstable_method; + +fn main() { + // FIXME: this function should not suggest the `foo` function. + similar_unstable_method::foo1(); + //~^ ERROR cannot find function `foo1` in crate `similar_unstable_method` [E0425] + + let foo = similar_unstable_method::Foo; + foo.foo1(); + //~^ ERROR no method named `foo1` found for struct `Foo` in the current scope [E0599] +} diff --git a/tests/ui/stability-attribute/issue-109177.stderr b/tests/ui/stability-attribute/issue-109177.stderr new file mode 100644 index 00000000000..9c2ac591ace --- /dev/null +++ b/tests/ui/stability-attribute/issue-109177.stderr @@ -0,0 +1,21 @@ +error[E0425]: cannot find function `foo1` in crate `similar_unstable_method` + --> $DIR/issue-109177.rs:7:30 + | +LL | similar_unstable_method::foo1(); + | ^^^^ help: a function with a similar name exists: `foo` + | + ::: $DIR/auxiliary/similar-unstable-method.rs:5:1 + | +LL | pub fn foo() {} + | ------------ similarly named function `foo` defined here + +error[E0599]: no method named `foo1` found for struct `Foo` in the current scope + --> $DIR/issue-109177.rs:11:9 + | +LL | foo.foo1(); + | ^^^^ method not found in `Foo` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index 437053a4476..35fdcae6a59 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -47,7 +47,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/uninhabited-static.rs:12:31 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void warning: the type `Void` does not permit zero-initialization --> $DIR/uninhabited-static.rs:12:31 @@ -66,7 +66,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/uninhabited-static.rs:16:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void warning: the type `Void` does not permit zero-initialization --> $DIR/uninhabited-static.rs:16:32 diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.rs b/tests/ui/suggestions/bad-infer-in-trait-impl.rs new file mode 100644 index 00000000000..87db2636fb2 --- /dev/null +++ b/tests/ui/suggestions/bad-infer-in-trait-impl.rs @@ -0,0 +1,10 @@ +trait Foo { + fn bar(); +} + +impl Foo for () { + fn bar(s: _) {} + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions +} + +fn main() {} diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.stderr b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr new file mode 100644 index 00000000000..418690ff85f --- /dev/null +++ b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr @@ -0,0 +1,14 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/bad-infer-in-trait-impl.rs:6:15 + | +LL | fn bar(s: _) {} + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn bar<T>(s: T) {} + | +++ ~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/suggestions/issue-109396.rs b/tests/ui/suggestions/issue-109396.rs new file mode 100644 index 00000000000..b6c464d45a2 --- /dev/null +++ b/tests/ui/suggestions/issue-109396.rs @@ -0,0 +1,12 @@ +fn main() { + { + let mut mutex = std::mem::zeroed( + //~^ ERROR this function takes 0 arguments but 4 arguments were supplied + file.as_raw_fd(), + //~^ ERROR expected value, found macro `file` + 0, + 0, + 0, + ); + } +} diff --git a/tests/ui/suggestions/issue-109396.stderr b/tests/ui/suggestions/issue-109396.stderr new file mode 100644 index 00000000000..eca160e2fab --- /dev/null +++ b/tests/ui/suggestions/issue-109396.stderr @@ -0,0 +1,34 @@ +error[E0423]: expected value, found macro `file` + --> $DIR/issue-109396.rs:5:13 + | +LL | file.as_raw_fd(), + | ^^^^ not a value + +error[E0061]: this function takes 0 arguments but 4 arguments were supplied + --> $DIR/issue-109396.rs:3:25 + | +LL | let mut mutex = std::mem::zeroed( + | ^^^^^^^^^^^^^^^^ +LL | +LL | file.as_raw_fd(), + | ---------------- unexpected argument +LL | +LL | 0, + | - unexpected argument of type `{integer}` +LL | 0, + | - unexpected argument of type `{integer}` +LL | 0, + | - unexpected argument of type `{integer}` + | +note: function defined here + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL +help: remove the extra arguments + | +LL - file.as_raw_fd(), +LL + , + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0061, E0423. +For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/suggestions/issue-109436.rs b/tests/ui/suggestions/issue-109436.rs new file mode 100644 index 00000000000..e45ee5991db --- /dev/null +++ b/tests/ui/suggestions/issue-109436.rs @@ -0,0 +1,13 @@ +struct Foo; +struct Bar; + +impl From<&Foo> for Bar { + fn from(foo: &Foo) -> Bar { + Bar + } +} + +fn main() { + let foo = Foo; + let b: Bar = foo.into(); //~ ERROR E0277 +} diff --git a/tests/ui/suggestions/issue-109436.stderr b/tests/ui/suggestions/issue-109436.stderr new file mode 100644 index 00000000000..48518b33d12 --- /dev/null +++ b/tests/ui/suggestions/issue-109436.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `Foo: Into<_>` is not satisfied + --> $DIR/issue-109436.rs:12:22 + | +LL | let b: Bar = foo.into(); + | ^^^^ the trait `~const Into<_>` is not implemented for `Foo` + | + = note: required for `Foo` to implement `Into<Bar>` +help: consider borrowing here + | +LL | let b: Bar = (&foo).into(); + | ++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/suggestions/suggest-ret-on-async-w-late.rs b/tests/ui/suggestions/suggest-ret-on-async-w-late.rs new file mode 100644 index 00000000000..459b94f943b --- /dev/null +++ b/tests/ui/suggestions/suggest-ret-on-async-w-late.rs @@ -0,0 +1,11 @@ +// edition: 2021 + +// Make sure we don't ICE when suggesting a return type +// for an async fn that has late-bound vars... + +async fn ice(_: &i32) { + true + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr b/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr new file mode 100644 index 00000000000..bff864b222b --- /dev/null +++ b/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/suggest-ret-on-async-w-late.rs:7:5 + | +LL | async fn ice(_: &i32) { + | - help: try adding a return type: `-> bool` +LL | true + | ^^^^ expected `()`, found `bool` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/test-attrs/custom-test-frameworks/issue-107454.rs b/tests/ui/test-attrs/custom-test-frameworks/issue-107454.rs new file mode 100644 index 00000000000..2bb133e8bfd --- /dev/null +++ b/tests/ui/test-attrs/custom-test-frameworks/issue-107454.rs @@ -0,0 +1,10 @@ +// compile-flags: --test + +#![feature(custom_test_frameworks)] +#![deny(unnameable_test_items)] + +fn foo() { + #[test_case] + //~^ ERROR cannot test inner items [unnameable_test_items] + fn test2() {} +} diff --git a/tests/ui/test-attrs/custom-test-frameworks/issue-107454.stderr b/tests/ui/test-attrs/custom-test-frameworks/issue-107454.stderr new file mode 100644 index 00000000000..bd604afb79f --- /dev/null +++ b/tests/ui/test-attrs/custom-test-frameworks/issue-107454.stderr @@ -0,0 +1,15 @@ +error: cannot test inner items + --> $DIR/issue-107454.rs:7:5 + | +LL | #[test_case] + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-107454.rs:4:9 + | +LL | #![deny(unnameable_test_items)] + | ^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the attribute macro `test_case` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/test-attrs/tests-listing-format-default.rs b/tests/ui/test-attrs/tests-listing-format-default.rs new file mode 100644 index 00000000000..d5df4b57b05 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-default.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list +// run-pass +// check-run-results + +// Checks the listing of tests with no --format arguments. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-default.run.stdout b/tests/ui/test-attrs/tests-listing-format-default.run.stdout new file mode 100644 index 00000000000..72337daf02c --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-default.run.stdout @@ -0,0 +1,5 @@ +a_test: test +m_test: test +z_test: test + +3 tests, 0 benchmarks diff --git a/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs new file mode 100644 index 00000000000..5247f1f8f17 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format json +// run-fail +// check-run-results + +// Checks that --format json does not work without -Zunstable-options. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr new file mode 100644 index 00000000000..9f6276300a0 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr @@ -0,0 +1 @@ +error: The "json" format is only accepted on the nightly compiler diff --git a/tests/ui/test-attrs/tests-listing-format-json.rs b/tests/ui/test-attrs/tests-listing-format-json.rs new file mode 100644 index 00000000000..18f1521eeeb --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json.rs @@ -0,0 +1,20 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format json -Zunstable-options +// run-pass +// check-run-results +// normalize-stdout-test: "fake-test-src-base/test-attrs/" -> "$$DIR/" +// normalize-stdout-test: "fake-test-src-base\\test-attrs\\" -> "$$DIR/" + +// Checks the listing of tests with --format json. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-json.run.stdout b/tests/ui/test-attrs/tests-listing-format-json.run.stdout new file mode 100644 index 00000000000..b4131e97c34 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json.run.stdout @@ -0,0 +1,5 @@ +{ "type": "suite", "event": "discovery" } +{ "type": "test", "event": "discovered", "name": "a_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 20, "start_col": 4, "end_line": 20, "end_col": 10 } +{ "type": "test", "event": "discovered", "name": "m_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 13, "start_col": 4, "end_line": 13, "end_col": 10 } +{ "type": "test", "event": "discovered", "name": "z_test", "ignore": true, "ignore_message": "not yet implemented", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 17, "start_col": 4, "end_line": 17, "end_col": 10 } +{ "type": "suite", "event": "completed", "tests": 3, "benchmarks": 0, "total": 3, "ignored": 1 } diff --git a/tests/ui/test-attrs/tests-listing-format-terse.rs b/tests/ui/test-attrs/tests-listing-format-terse.rs new file mode 100644 index 00000000000..7835f71759c --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-terse.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format terse +// run-pass +// check-run-results + +// Checks the listing of tests with --format terse. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-terse.run.stdout b/tests/ui/test-attrs/tests-listing-format-terse.run.stdout new file mode 100644 index 00000000000..22afe104bfb --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-terse.run.stdout @@ -0,0 +1,3 @@ +a_test: test +m_test: test +z_test: test diff --git a/tests/ui/traits/cycle-cache-err-60010.stderr b/tests/ui/traits/cycle-cache-err-60010.stderr index eeee997608e..2ff16b4af38 100644 --- a/tests/ui/traits/cycle-cache-err-60010.stderr +++ b/tests/ui/traits/cycle-cache-err-60010.stderr @@ -1,22 +1,9 @@ -error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe` +error[E0275]: overflow evaluating the requirement `RootDatabase: RefUnwindSafe` --> $DIR/cycle-cache-err-60010.rs:27:13 | LL | _parse: <ParseQuery as Query<RootDatabase>>::Data, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: required because it appears within the type `PhantomData<SalsaStorage>` - = note: required because it appears within the type `Unique<SalsaStorage>` - = note: required because it appears within the type `Box<SalsaStorage>` -note: required because it appears within the type `Runtime<RootDatabase>` - --> $DIR/cycle-cache-err-60010.rs:23:8 - | -LL | struct Runtime<DB: Database> { - | ^^^^^^^ -note: required because it appears within the type `RootDatabase` - --> $DIR/cycle-cache-err-60010.rs:20:8 - | -LL | struct RootDatabase { - | ^^^^^^^^^^^^ note: required for `RootDatabase` to implement `SourceDatabase` --> $DIR/cycle-cache-err-60010.rs:44:9 | diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs index 6474b2b38e1..4eca643a92d 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,6 +1,6 @@ // build-fail // compile-flags: -Zinline-mir=no -// error-pattern: overflow evaluating the requirement `(): Sized` +// error-pattern: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()` // error-pattern: function cannot return without recursing // normalize-stderr-test: "long-type-\d+" -> "long-type-hash" diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr index 1f18c5daf66..144990d50f0 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -12,11 +12,17 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0275]: overflow evaluating the requirement `(): Sized` +error[E0275]: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) - = note: required for `std::iter::Empty<()>` to implement `Iterator` - = note: 171 redundant requirements hidden +note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator` + --> $DIR/issue-91949-hangs-on-recursion.rs:16:32 + | +LL | impl<T, I: Iterator<Item = T>> Iterator for IteratorOfWrapped<T, I> { + | -------- ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here + = note: 256 redundant requirements hidden = note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<..., ...>>, ...>>, ...>>` to implement `Iterator` = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type-hash.txt' diff --git a/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs b/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs new file mode 100644 index 00000000000..4bfb6323a53 --- /dev/null +++ b/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs @@ -0,0 +1,40 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +trait Foo { + type Gat<'a> + where + Self: 'a; + fn bar(&self) -> Self::Gat<'_>; +} + +enum Option<T> { + Some(T), + None, +} + +impl<T> Option<T> { + fn as_ref(&self) -> Option<&T> { + match self { + Option::Some(t) => Option::Some(t), + Option::None => Option::None, + } + } + + fn map<U>(self, f: impl FnOnce(T) -> U) -> Option<U> { + match self { + Option::Some(t) => Option::Some(f(t)), + Option::None => Option::None, + } + } +} + +impl<T: Foo + 'static> Foo for Option<T> { + type Gat<'a> = Option<<T as Foo>::Gat<'a>> where Self: 'a; + + fn bar(&self) -> Self::Gat<'_> { + self.as_ref().map(Foo::bar) + } +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/alias-sub.rs b/tests/ui/traits/new-solver/alias-sub.rs new file mode 100644 index 00000000000..30c1981a92e --- /dev/null +++ b/tests/ui/traits/new-solver/alias-sub.rs @@ -0,0 +1,34 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +trait Trait { + type Assoc: Sized; +} + +impl Trait for &'static str { + type Assoc = &'static str; +} + +// Wrapper is just here to get around stupid `Sized` obligations in mir typeck +struct Wrapper<T: ?Sized>(std::marker::PhantomData<T>); +fn mk<T: Trait>(x: T) -> Wrapper<<T as Trait>::Assoc> { todo!() } + + +trait IsStaticStr {} +impl IsStaticStr for (&'static str,) {} +fn define<T: IsStaticStr>(_: T) {} + +fn foo<'a, T: Trait>() { + let y = Default::default(); + + // `<?0 as Trait>::Assoc <: &'a str` + // In the old solver, this would *equate* the LHS and RHS. + let _: Wrapper<&'a str> = mk(y); + + // ... then later on, we constrain `?0 = &'static str` + // but that should not mean that `'a = 'static`, because + // we should use *sub* above. + define((y,)); +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs b/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs index 3f7316a2279..4b013983a4a 100644 --- a/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs +++ b/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs @@ -1,3 +1,4 @@ +// compile-flags: -Ztrait-solver=next // check-pass trait Mirror { diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.rs b/tests/ui/traits/new-solver/coherence/issue-102048.rs new file mode 100644 index 00000000000..11636bfeb55 --- /dev/null +++ b/tests/ui/traits/new-solver/coherence/issue-102048.rs @@ -0,0 +1,44 @@ +// This must fail coherence. +// +// Getting this to pass was fairly difficult, so here's an explanation +// of what's happening: +// +// Normalizing projections currently tries to replace them with inference variables +// while emitting a nested `Projection` obligation. This cannot be done if the projection +// has bound variables which is the case here. +// +// So the projections stay until after normalization. When unifying two projections we +// currently treat them as if they are injective, so we **incorrectly** unify their +// substs. This means that coherence for the two impls ends up unifying `?T` and `?U` +// as it tries to unify `<?T as WithAssoc1<'a>>::Assoc` with `<?U as WithAssoc1<'a>>::Assoc`. +// +// `impl1` therefore has the projection `<?T as WithAssoc2<'a>>::Assoc` and we have the +// assumption `?T: for<'a> WithAssoc2<'a, Assoc = i32>` in the `param_env`, so we normalize +// that to `i32`. We then try to unify `i32` from `impl1` with `u32` from `impl2` which fails, +// causing coherence to consider these two impls distinct. + +// compile-flags: -Ztrait-solver=next +pub trait Trait<T> {} + +pub trait WithAssoc1<'a> { + type Assoc; +} +pub trait WithAssoc2<'a> { + type Assoc; +} + +// impl 1 +impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U) +where + T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>, + U: for<'a> WithAssoc2<'a>, +{ +} + +// impl 2 +impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where + U: for<'a> WithAssoc1<'a> //~^ ERROR conflicting implementations of trait +{ +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.stderr b/tests/ui/traits/new-solver/coherence/issue-102048.stderr new file mode 100644 index 00000000000..17a43838fe2 --- /dev/null +++ b/tests/ui/traits/new-solver/coherence/issue-102048.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait<for<'a> fn(<_ as WithAssoc1<'a>>::Assoc, <_ as WithAssoc2<'a>>::Assoc)>` for type `(_, _)` + --> $DIR/issue-102048.rs:39:1 + | +LL | impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U) + | --------------------------------------------------------------------------------------------------- first implementation here +... +LL | impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/new-solver/destruct.rs b/tests/ui/traits/new-solver/destruct.rs new file mode 100644 index 00000000000..30d7777b78a --- /dev/null +++ b/tests/ui/traits/new-solver/destruct.rs @@ -0,0 +1,13 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +#![feature(const_trait_impl)] + +fn foo(_: impl std::marker::Destruct) {} + +struct MyAdt; + +fn main() { + foo(1); + foo(MyAdt); +} diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs index d566ead105c..0599e51d7ad 100644 --- a/tests/ui/traits/new-solver/fn-trait.rs +++ b/tests/ui/traits/new-solver/fn-trait.rs @@ -1,5 +1,4 @@ // compile-flags: -Ztrait-solver=next -// check-pass fn require_fn(_: impl Fn() -> i32) {} @@ -7,7 +6,27 @@ fn f() -> i32 { 1i32 } +extern "C" fn g() -> i32 { + 2i32 +} + +unsafe fn h() -> i32 { + 2i32 +} + fn main() { require_fn(f); require_fn(f as fn() -> i32); + require_fn(f as unsafe fn() -> i32); + //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32` + //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32` + require_fn(g); + //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` + //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32` + require_fn(g as extern "C" fn() -> i32); + //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32` + //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32` + require_fn(h); + //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}` + //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32` } diff --git a/tests/ui/traits/new-solver/fn-trait.stderr b/tests/ui/traits/new-solver/fn-trait.stderr new file mode 100644 index 00000000000..d52bcaf25b8 --- /dev/null +++ b/tests/ui/traits/new-solver/fn-trait.stderr @@ -0,0 +1,124 @@ +error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32` + --> $DIR/fn-trait.rs:20:16 + | +LL | require_fn(f as unsafe fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32` + = note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:20:16 + | +LL | require_fn(f as unsafe fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` + --> $DIR/fn-trait.rs:23:16 + | +LL | require_fn(g); + | ---------- ^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() -> i32 {g}` + = note: wrap the `extern "C" fn() -> i32 {g}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:23:16 + | +LL | require_fn(g); + | ---------- ^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32` + --> $DIR/fn-trait.rs:26:16 + | +LL | require_fn(g as extern "C" fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for `extern "C" fn() -> i32` + = note: wrap the `extern "C" fn() -> i32` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:26:16 + | +LL | require_fn(g as extern "C" fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}` + --> $DIR/fn-trait.rs:29:16 + | +LL | require_fn(h); + | ---------- ^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}` + = note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:29:16 + | +LL | require_fn(h); + | ---------- ^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs new file mode 100644 index 00000000000..50f0152e904 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs @@ -0,0 +1,11 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn f() +where + for<B> B::Item: Send, + //~^ ERROR ambiguous associated type +{ +} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr new file mode 100644 index 00000000000..be6955c111e --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr @@ -0,0 +1,18 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/missing-assoc-item.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0223]: ambiguous associated type + --> $DIR/missing-assoc-item.rs:6:12 + | +LL | for<B> B::Item: Send, + | ^^^^^^^ help: use the fully-qualified path: `<B as IntoIterator>::Item` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs new file mode 100644 index 00000000000..a635edb4485 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs @@ -0,0 +1,24 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +trait Foo: for<T> Bar<T> {} + +trait Bar<T: ?Sized> { + fn method(&self) {} +} + +fn needs_bar(x: &(impl Bar<i32> + ?Sized)) { + x.method(); +} + +impl Foo for () {} + +impl<T: ?Sized> Bar<T> for () {} + +fn main() { + let x: &dyn Foo = &(); + //~^ ERROR the trait `Foo` cannot be made into an object + //~| ERROR the trait `Foo` cannot be made into an object + needs_bar(x); + //~^ ERROR the trait `Foo` cannot be made into an object +} diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr new file mode 100644 index 00000000000..47fa29b6648 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr @@ -0,0 +1,56 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/supertrait-object-safety.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/supertrait-object-safety.rs:19:23 + | +LL | let x: &dyn Foo = &(); + | ^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/supertrait-object-safety.rs:4:12 + | +LL | trait Foo: for<T> Bar<T> {} + | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables + | | + | this trait cannot be made into an object... + = note: required for `&()` to implement `CoerceUnsized<&dyn Foo>` + = note: required by cast to type `&dyn Foo` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/supertrait-object-safety.rs:19:12 + | +LL | let x: &dyn Foo = &(); + | ^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/supertrait-object-safety.rs:4:12 + | +LL | trait Foo: for<T> Bar<T> {} + | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables + | | + | this trait cannot be made into an object... + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/supertrait-object-safety.rs:22:5 + | +LL | needs_bar(x); + | ^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/supertrait-object-safety.rs:4:12 + | +LL | trait Foo: for<T> Bar<T> {} + | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables + | | + | this trait cannot be made into an object... + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr new file mode 100644 index 00000000000..e5a3c3f5cc4 --- /dev/null +++ b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `OtherTrait` for type `()` + --> $DIR/coherence-conflict.rs:12:1 + | +LL | impl OtherTrait for () {} + | ---------------------- first implementation here +LL | impl<T: MyTrait> OtherTrait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.old.stderr index a811d7e3201..393350ea3f1 100644 --- a/tests/ui/traits/reservation-impl/coherence-conflict.stderr +++ b/tests/ui/traits/reservation-impl/coherence-conflict.old.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `OtherTrait` for type `()` - --> $DIR/coherence-conflict.rs:11:1 + --> $DIR/coherence-conflict.rs:12:1 | LL | impl OtherTrait for () {} | ---------------------- first implementation here diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.rs b/tests/ui/traits/reservation-impl/coherence-conflict.rs index fa4a309315b..6bbd90f94dc 100644 --- a/tests/ui/traits/reservation-impl/coherence-conflict.rs +++ b/tests/ui/traits/reservation-impl/coherence-conflict.rs @@ -1,5 +1,6 @@ // check that reservation impls are accounted for in negative reasoning. - +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next #![feature(rustc_attrs)] trait MyTrait {} diff --git a/tests/ui/traits/reservation-impl/no-use.stderr b/tests/ui/traits/reservation-impl/no-use.next.stderr index cefb2a8792f..542e3a28adf 100644 --- a/tests/ui/traits/reservation-impl/no-use.stderr +++ b/tests/ui/traits/reservation-impl/no-use.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): MyTrait` is not satisfied - --> $DIR/no-use.rs:10:26 + --> $DIR/no-use.rs:11:26 | LL | <() as MyTrait>::foo(&()); | -------------------- ^^^ the trait `MyTrait` is not implemented for `()` diff --git a/tests/ui/traits/reservation-impl/no-use.old.stderr b/tests/ui/traits/reservation-impl/no-use.old.stderr new file mode 100644 index 00000000000..542e3a28adf --- /dev/null +++ b/tests/ui/traits/reservation-impl/no-use.old.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `(): MyTrait` is not satisfied + --> $DIR/no-use.rs:11:26 + | +LL | <() as MyTrait>::foo(&()); + | -------------------- ^^^ the trait `MyTrait` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `MyTrait` is implemented for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/reservation-impl/no-use.rs b/tests/ui/traits/reservation-impl/no-use.rs index 65a55d9e209..864f1791fd0 100644 --- a/tests/ui/traits/reservation-impl/no-use.rs +++ b/tests/ui/traits/reservation-impl/no-use.rs @@ -1,5 +1,6 @@ // check that reservation impls can't be used as normal impls in positive reasoning. - +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next #![feature(rustc_attrs)] trait MyTrait { fn foo(&self); } diff --git a/tests/ui/traits/reservation-impl/non-lattice-ok.rs b/tests/ui/traits/reservation-impl/non-lattice-ok.rs index a71051243c8..7787904d9b2 100644 --- a/tests/ui/traits/reservation-impl/non-lattice-ok.rs +++ b/tests/ui/traits/reservation-impl/non-lattice-ok.rs @@ -30,6 +30,12 @@ // // [ii]: https://smallcultfollowing.com/babysteps/blog/2016/09/24/intersection-impls/ + +// check that reservation impls can't be used as normal impls in positive reasoning. + +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + #![feature(rustc_attrs, never_type)] trait MyTrait {} diff --git a/tests/ui/traits/reservation-impl/ok.rs b/tests/ui/traits/reservation-impl/ok.rs index 611c8d88413..8ff6645a2b3 100644 --- a/tests/ui/traits/reservation-impl/ok.rs +++ b/tests/ui/traits/reservation-impl/ok.rs @@ -3,6 +3,9 @@ // rpass test for reservation impls. Not 100% required because `From` uses them, // but still. +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + #![feature(rustc_attrs)] use std::mem; diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index f0fa93722b8..bf947d0ea4a 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -8,7 +8,7 @@ error: the constant `ASSUME_ALIGNMENT` is not of type `Assume` --> $DIR/issue-101739-1.rs:8:14 | LL | Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME_ALIGNMENT>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` | note: required by a bound in `BikeshedIntrinsicFrom` --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs index a450dbb82d1..e6f7dc410b6 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.rs +++ b/tests/ui/typeck/typeck_type_placeholder_item.rs @@ -228,5 +228,4 @@ fn evens_squared(n: usize) -> _ { const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); //~^ ERROR the trait bound -//~| ERROR the trait bound //~| ERROR the placeholder diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index bc6c9fd0779..9144ab9e3a6 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -437,19 +437,6 @@ LL | fn evens_squared(n: usize) -> _ { | not allowed in type signatures | help: replace with an appropriate return type: `impl Iterator<Item = usize>` -error[E0277]: the trait bound `std::ops::Range<{integer}>: Iterator` is not satisfied - --> $DIR/typeck_type_placeholder_item.rs:229:22 - | -LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); - | ^^^^^^ `std::ops::Range<{integer}>` is not an iterator - | - = help: the trait `~const Iterator` is not implemented for `std::ops::Range<{integer}>` -note: the trait `Iterator` is implemented for `std::ops::Range<{integer}>`, but that implementation is not `const` - --> $DIR/typeck_type_placeholder_item.rs:229:14 - | -LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); - | ^^^^^^^ - error[E0277]: the trait bound `Filter<std::ops::Range<{integer}>, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>: Iterator` is not satisfied --> $DIR/typeck_type_placeholder_item.rs:229:45 | @@ -677,7 +664,7 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` -error: aborting due to 73 previous errors +error: aborting due to 72 previous errors Some errors have detailed explanations: E0121, E0277, E0282, E0403. For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/unpretty/flattened-format-args.rs b/tests/ui/unpretty/flattened-format-args.rs new file mode 100644 index 00000000000..705dded169a --- /dev/null +++ b/tests/ui/unpretty/flattened-format-args.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunpretty=hir -Zflatten-format-args=yes +// check-pass + +fn main() { + let x = 1; + // Should flatten to println!("a 123 b {x} xyz\n"): + println!("a {} {}", format_args!("{} b {x}", 123), "xyz"); +} diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout new file mode 100644 index 00000000000..a8fe8da0024 --- /dev/null +++ b/tests/ui/unpretty/flattened-format-args.stdout @@ -0,0 +1,16 @@ +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +// compile-flags: -Zunpretty=hir -Zflatten-format-args=yes +// check-pass + +fn main() { + let x = 1; + // Should flatten to println!("a 123 b {x} xyz\n"): + { + ::std::io::_print(<#[lang = "format_arguments"]>::new_v1(&["a 123 b ", + " xyz\n"], + &[<#[lang = "format_argument"]>::new_display(&x)])); + }; + } |
